이 블로그 검색

2019년 10월 6일 일요일

template method pattern 에 CRTP 사용하기 (c++)

그동안 개발하면서 template method pattern을 즐겨 사용하고 있는데, virtual 함수를 이용하여 구현했었다. 그런데 CRTP 를 이용해도 비슷한(동일한건 아님) 처리가 가능하다.

예를 들어 다음처럼 template method pattern 구현을 한경우,



#include <iostream>
#include <memory>
#include <vector>

template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}

class Base {
    public:
        virtual ~Base() {}

        void DoWork() { 
            DoBasicWork();
            DoSpecialWork();
        }
        void DoBasicWork(){
            std::cout << "Do Basic work..\n";
        }
        virtual void DoSpecialWork() = 0;
};

class Derived1 : public Base
{
    public:
        void DoSpecialWork() override {
            std::cout << "Do derived 1's special work..\n";
        }
};

class Derived2 : public Base
{
    public:
        void DoSpecialWork() override {
            std::cout << "Do derived 2's special work..\n";
        }
};

int main()
{
    std::vector<std::unique_ptr<Base>> vec_base;
    vec_base.push_back(make_unique<Derived1>());
    vec_base.push_back(make_unique<Derived2>());
    for(auto it = vec_base.begin(); it != vec_base.end(); ++it){
        (*it)->DoWork();
    }
    return 0;
}


CRTP 를 이용해서 (비슷하게) 다시 구현하면 다음과 같다. 동적 다형성(dynamic polymorphism)을 희생한 경우이다.


//.... 생략 ....
template<typename Derived>
class Base 
{
    public:
        virtual ~Base() {}
        void DoWork() { 
            DoBasicWork();
            static_cast<Derived*>(this)->DoSpecialWork();
        }
        void DoBasicWork(){
            std::cout << "Do Basic work..\n";
        }
};

class Derived1 : public Base<Derived1>
{
    public:
        void DoSpecialWork(){
            std::cout << "Do derived 1's special work..\n";
        }
};

class Derived2 : public Base<Derived2>
{
    public:
        void DoSpecialWork(){
            std::cout << "Do derived 2's special work..\n";
        }
};

int main()
{    
    Derived1 child1;
    Derived2 child2;
    child1.DoWork();
    child2.DoWork();
    return 0;
}

처음 예제와 같이 STL Container 에 저장하는 등의 동적 다형성이 필요하다면, 가상함수를 사용할수 밖에 없지만, 두번째 예제와 같은식으로 사용하는것으로 충분하다면 CRTP 를 이용한 방식도 고려해볼만 하겠다.



댓글 없음:

댓글 쓰기