2015-05-03 2 views
4

Можно ли делать такие вещи в C++14. У меня есть базовый класс следующим образом:Ввод функции в подкласс

#include <iostream> 

class AbstractElement; 
class ConcreteElement; 
class SuperConcreteElement; 

class B 
{ 
public: 
    void bar(AbstractElement*) 
    { 
     std::cout << "Abstract element" << std::endl; 
    } 

    void bar(ConcreteElement*) 
    { 
     std::cout << "Concrete element" << std::endl; 
    } 

    void bar(SuperConcreteElement*) 
    { 
     std::cout << "Super concrete element" << std::endl; 
    } 
}; 

class AbstractElement 
{ 
public: 
    virtual void foo() = 0; 
}; 

class ConcreteElement : public AbstractElement 
{ 
private: 
    B _b; 
public: 
    void foo() 
    { 
     _b.bar(this); //1 
    } 
}; 

class SuperConcreteElement : public AbstractElement 
{ 
private: 
    B _b; 
public: 
    void foo() 
    { 
     _b.bar(this); //2 
    } 
}; 

int main() 
{ 
    AbstractElement *e = new ConcreteElement(); 
    e -> foo(); //Prints Concrete element 
} 

Как вы можете видеть на //1 и //2, тело функции является совершенно аналогично. Но я не могу переместить его в базовый класс из-за зависимости от статического типа this. Несмотря на этот факт, я бы не хотел писать абсолютно такой же код каждый раз, когда мне нужно добавить еще один подкласс AbstractElement. Итак, мне нужен какой-то механизм, который предоставляет нам возможность вводить код в функцию.

До тех пор, пока маркос не очень желательно, я хотел бы спросить о некоторых трюках, которые можно сделать в C++14 для решения такой проблемы.

ответ

1

Да, это возможно с помощью CRTP:

#include <iostream> 

class AbstractElement; 
class ConcreteElement; 
class SuperConcreteElement; 

class B 
{ 
public: 
    void bar(AbstractElement*) 
    { 
     std::cout << "Abstract element" << std::endl; 
    } 

    void bar(ConcreteElement*) 
    { 
     std::cout << "Concrete element" << std::endl; 
    } 

    void bar(SuperConcreteElement*) 
    { 
     std::cout << "Super concrete element" << std::endl; 
    } 
}; 

class AbstractElement 
{ 
public: 
    virtual void foo() = 0; 
}; 

template <class T> 
class CRTPAbstractElement : public AbstractElement 
{ 
    B _b; 
public: 
    virtual void foo() 
    { 
     T* t = dynamic_cast<T *>(this); 
     _b.bar(t); 
    } 
}; 

class ConcreteElement : public CRTPAbstractElement<ConcreteElement> 
{ 
}; 

class SuperConcreteElement : public CRTPAbstractElement<SuperConcreteElement> 
{ 
}; 

int main() 
{ 
    AbstractElement *e = new ConcreteElement(); 
    e -> foo(); //Prints Concrete element 
} 

Добавив промежуточный класс CRTP мы можем привести указатель на базовый класс к указателю на производный класс. Таким образом, решение проблемы дублирования кода.

+0

Прохладный, на самом деле я подозревал, что шаблоны были бы полезны здесь, но не знали, как его использовать. – user3663882

Смежные вопросы