[2026] C++ Mixin | 믹스인 가이드

[2026] C++ Mixin | 믹스인 가이드

이 글의 핵심

C++ Mixin - 믹스인 가이드. C++ Mixin의 Mixin이란?, 기본 패턴, 실전 예시를 실전 코드와 함께 설명합니다.

Mixin이란?

기능 조합 패턴 다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
// Mixin 클래스들
template<typename Base>
class Printable : public Base {
public:
    void print() const {
        std::cout << "Printing...\n";
    }
};
template<typename Base>
class Serializable : public Base {
public:
    void serialize() const {
        std::cout << "Serializing...\n";
    }
};
// 베이스
class Widget {
public:
    void doWork() {
        std::cout << "Working...\n";
    }
};
// 조합
using MyWidget = Serializable<Printable<Widget>>;
int main() {
    MyWidget w;
    w.doWork();
    w.print();
    w.serialize();
}

기본 패턴

아래 코드는 cpp를 사용한 구현 예제입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 코드를 직접 실행해보면서 동작을 확인해보세요.

// Mixin 템플릿
template<typename Base>
class Mixin : public Base {
public:
    void newFeature() { /* ....*/ }
};
// 사용
class MyClass : public Mixin<SomeBase> {};

실전 예시

예시 1: 다중 Mixin

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
#include <string>
template<typename Base>
class Loggable : public Base {
public:
    void log(const std::string& msg) const {
        std::cout << "[LOG] " << msg << '\n';
    }
};
template<typename Base>
class Timestamped : public Base {
public:
    void setTimestamp(long ts) {
        timestamp = ts;
    }
    
    long getTimestamp() const {
        return timestamp;
    }
    
private:
    long timestamp = 0;
};
template<typename Base>
class Versioned : public Base {
public:
    void setVersion(int v) {
        version = v;
    }
    
    int getVersion() const {
        return version;
    }
    
private:
    int version = 1;
};
// 베이스
class Document {
public:
    void setContent(const std::string& c) {
        content = c;
    }
    
    std::string getContent() const {
        return content;
    }
    
private:
    std::string content;
};
// 조합
using RichDocument = Versioned<Timestamped<Loggable<Document>>>;
int main() {
    RichDocument doc;
    doc.setContent("Hello");
    doc.log("Document created");
    doc.setTimestamp(1234567890);
    doc.setVersion(2);
    
    std::cout << doc.getContent() << '\n';
    std::cout << "Version: " << doc.getVersion() << '\n';
}

예시 2: CRTP Mixin

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
template<typename Derived>
class Comparable {
public:
    bool operator!=(const Derived& other) const {
        return !(self() == other);
    }
    
    bool operator>(const Derived& other) const {
        return other < self();
    }
    
    bool operator<=(const Derived& other) const {
        return !(self() > other);
    }
    
    bool operator>=(const Derived& other) const {
        return !(self() < other);
    }
    
private:
    const Derived& self() const {
        return static_cast<const Derived&>(*this);
    }
};
class Number : public Comparable<Number> {
public:
    Number(int v) : value(v) {}
    
    bool operator==(const Number& other) const {
        return value == other.value;
    }
    
    bool operator<(const Number& other) const {
        return value < other.value;
    }
    
private:
    int value;
};
int main() {
    Number a(10), b(20);
    std::cout << (a != b) << '\n';  // 1
    std::cout << (a <= b) << '\n';  // 1
}

예시 3: 기능 선택

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
// 빈 베이스
class Empty {};
// Mixin들
template<typename Base>
class WithLogging : public Base {
public:
    void log(const char* msg) {
        std::cout << "[LOG] " << msg << '\n';
    }
};
template<typename Base>
class WithCaching : public Base {
public:
    void cache(int key, int value) {
        // 캐싱 로직
    }
};
// 조합 선택
template<bool EnableLogging, bool EnableCaching>
class Service : public 
    std::conditional_t<EnableLogging, WithLogging<
        std::conditional_t<EnableCaching, WithCaching<Empty>, Empty>
    >, 
    std::conditional_t<EnableCaching, WithCaching<Empty>, Empty>
    >
{
public:
    void doWork() {
        if constexpr (EnableLogging) {
            this->log("Working...");
        }
        std::cout << "Work done\n";
    }
};
int main() {
    Service<true, true> s1;   // 로깅 + 캐싱
    s1.doWork();
    
    Service<true, false> s2;  // 로깅만
    s2.doWork();
    
    Service<false, false> s3; // 둘 다 없음
    s3.doWork();
}

예시 4: 체이닝

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <iostream>
#include <string>
template<typename Base>
class Chainable : public Base {
public:
    auto& setValue(int v) {
        value = v;
        return *this;
    }
    
    auto& setName(const std::string& n) {
        name = n;
        return *this;
    }
    
    void print() const {
        std::cout << name << ": " << value << '\n';
    }
    
private:
    int value = 0;
    std::string name;
};
class Empty {};
using Builder = Chainable<Empty>;
int main() {
    Builder b;
    b.setValue(42)
     .setName("Answer")
     .print();
}

장점

  1. 조합: 기능 자유롭게 조합
  2. 재사용: Mixin 재사용
  3. 컴파일 타임: 오버헤드 없음
  4. 타입 안전: 컴파일 타임 체크

자주 발생하는 문제

문제 1: 다이아몬드

아래 코드는 cpp를 사용한 구현 예제입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

template<typename Base>
class MixinA : public Base {};
template<typename Base>
class MixinB : public Base {};
// ❌ 다이아몬드
// class MyClass : public MixinA<Widget>, public MixinB<Widget> {};
// ✅ 체인
class MyClass : public MixinA<MixinB<Widget>> {};

문제 2: 생성자

아래 코드는 cpp를 사용한 구현 예제입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 코드를 직접 실행해보면서 동작을 확인해보세요.

template<typename Base>
class Mixin : public Base {
public:
    // ✅ 완벽한 전달
    template<typename....Args>
    Mixin(Args&&....args) : Base(std::forward<Args>(args)...) {}
};

문제 3: 이름 충돌

다음은 cpp를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

template<typename Base>
class MixinA : public Base {
public:
    void func() { std::cout << "A\n"; }
};
template<typename Base>
class MixinB : public Base {
public:
    void func() { std::cout << "B\n"; }
};
class MyClass : public MixinA<MixinB<Empty>> {
public:
    void test() {
        MixinA<MixinB<Empty>>::func();  // A
    }
};

문제 4: 타입 복잡도

아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 코드를 직접 실행해보면서 동작을 확인해보세요.

// 복잡한 타입
using MyType = Mixin1<Mixin2<Mixin3<Mixin4<Base>>>>;
// ✅ 별칭
template<typename T>
using WithFeatures = Mixin1<Mixin2<Mixin3<Mixin4<T>>>>;
using MyType = WithFeatures<Base>;

사용 사례

  1. 기능 조합
  2. 선택적 기능
  3. 정책 기반 설계
  4. 빌더 패턴

FAQ

Q1: Mixin?

A: 기능 조합 패턴.

Q2: 방법?

A: 템플릿 상속.

Q3: 장점?

A: 조합, 재사용, 컴파일 타임.

Q4: 단점?

A: 타입 복잡도, 이름 충돌.

Q5: 다이아몬드?

A: 체인으로 해결.

Q6: 학습 리소스는?

A:

  • “C++ Templates”
  • “Modern C++ Design”
  • cppreference.com

같이 보면 좋은 글 (내부 링크)

이 주제와 연결되는 다른 글입니다.

관련 글

... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3