본문 바로가기
-----ETC-----/C++ 성능 최적화 및 고급 테크닉 시리즈

[C++ 성능 최적화 및 고급 테크닉] Day 14: CRTP (Curiously Recurring Template Pattern) 사용법

by cogito21_cpp 2024. 8. 1.
반응형

CRTP란?

CRTP(Curiously Recurring Template Pattern)는 C++ 템플릿 메타프로그래밍 기법 중 하나로, 기본 클래스가 자신을 상속하는 파생 클래스를 템플릿 매개변수로 받는 패턴입니다. 이를 통해 코드 재사용성과 컴파일 시간 다형성을 구현할 수 있습니다.

CRTP의 기본 구조

CRTP의 기본 구조는 다음과 같습니다:

template <typename Derived>
class Base {
public:
    void interface() {
        static_cast<Derived*>(this)->implementation();
    }

    void implementation() {
        std::cout << "Base implementation" << std::endl;
    }
};

class Derived : public Base<Derived> {
public:
    void implementation() {
        std::cout << "Derived implementation" << std::endl;
    }
};

 

위 코드에서 Base 클래스는 파생 클래스 Derived를 템플릿 매개변수로 받아 interface 함수에서 implementation 함수를 호출합니다. Derived 클래스는 implementation 함수를 재정의합니다.

 

CRTP의 장점

  • 컴파일 시간 다형성: 런타임 오버헤드 없이 다형성을 구현할 수 있습니다.
  • 코드 재사용성: 공통 기능을 기본 클래스에 구현하여 코드 재사용성을 높일 수 있습니다.
  • 강력한 타입 안정성: 컴파일 시간에 타입 검사를 수행하여 안전성을 높일 수 있습니다.

CRTP 예제

CRTP를 사용하여 간단한 계산기 클래스를 구현해보겠습니다.

 

1. 기본 CRTP 구조

#include <iostream>

template <typename Derived>
class Calculator {
public:
    void calculate() {
        static_cast<Derived*>(this)->compute();
    }
};

class Adder : public Calculator<Adder> {
public:
    void compute() {
        std::cout << "Adder::compute()" << std::endl;
    }
};

class Multiplier : public Calculator<Multiplier> {
public:
    void compute() {
        std::cout << "Multiplier::compute()" << std::endl;
    }
};

int main() {
    Adder adder;
    Multiplier multiplier;

    adder.calculate(); // Adder::compute()
    multiplier.calculate(); // Multiplier::compute()

    return 0;
}

 

2. 고급 CRTP 사용

CRTP를 사용하여 여러 파생 클래스에서 공통적인 기능을 구현하고, 파생 클래스에서 구체적인 구현을 제공합니다.

#include <iostream>

template <typename Derived>
class Shape {
public:
    void draw() {
        static_cast<Derived*>(this)->drawImpl();
    }
};

class Circle : public Shape<Circle> {
public:
    void drawImpl() {
        std::cout << "Drawing Circle" << std::endl;
    }
};

class Square : public Shape<Square> {
public:
    void drawImpl() {
        std::cout << "Drawing Square" << std::endl;
    }
};

int main() {
    Circle circle;
    Square square;

    circle.draw(); // Drawing Circle
    square.draw(); // Drawing Square

    return 0;
}

 

실습 문제

문제 1: CRTP를 사용하여 동물 클래스 구현하기

다음 코드에서 CRTP를 사용하여 동물 클래스 구조를 구현하세요. 각 동물 클래스는 sound 함수를 통해 자신의 소리를 출력해야 합니다.

 

main.cpp

#include <iostream>

class Animal {
public:
    void sound() {
        std::cout << "Some sound" << std::endl;
    }
};

class Dog : public Animal {
public:
    void sound() {
        std::cout << "Woof" << std::endl;
    }
};

class Cat : public Animal {
public:
    void sound() {
        std::cout << "Meow" << std::endl;
    }
};

int main() {
    Dog dog;
    Cat cat;

    dog.sound(); // Woof
    cat.sound(); // Meow

    return 0;
}

 

해답:

main.cpp (CRTP 적용)

#include <iostream>

template <typename Derived>
class Animal {
public:
    void sound() {
        static_cast<Derived*>(this)->soundImpl();
    }
};

class Dog : public Animal<Dog> {
public:
    void soundImpl() {
        std::cout << "Woof" << std::endl;
    }
};

class Cat : public Animal<Cat> {
public:
    void soundImpl() {
        std::cout << "Meow" << std::endl;
    }
};

int main() {
    Dog dog;
    Cat cat;

    dog.sound(); // Woof
    cat.sound(); // Meow

    return 0;
}

 

이제 열네 번째 날의 학습을 마쳤습니다. CRTP의 개념과 이를 구현하는 방법을 이해하고, 실습 문제를 통해 이를 적용하는 방법을 학습했습니다.

질문이나 피드백이 있으면 언제든지 댓글로 남겨 주세요. 내일부터는 병렬 프로그래밍과 동시성에 대해 학습하겠습니다. 내일은 "멀티스레딩의 기본 개념"에 대해 학습하겠습니다.

반응형