![]() |
Curiously recurring template pattern | ||
Паттерн «CRTP» решает те же задачи, что и «Nonvirtual interface», однако при этом он имеет некоторые преимущества, главное из которых состоит в том, что он позволяет пользователю работать с чисто абстрактным интерфейсом, делая полностью невидимыми для пользователя стыковку между пользовательским интерфейсом и интерфейсом виртуальным. |
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | #include <iostream> #include <memory> class abstract { public: virtual ~abstract() {} virtual void hello() = 0; }; template <class T> class base : public abstract { public: virtual void hello() { static_cast<T*>(this)->do_hello(); } private: void do_hello() { std::cout << "base::hello()" << std::endl; } }; class left : public base<left> { public: void do_hello() { std::cout << "left::hello()" << std::endl; } }; class right : public base<right> { }; int main() { typedef std::auto_ptr<abstract> abstract_ptr; abstract_ptr a1(new left); abstract_ptr a2(new right); a1->hello(); a2->hello(); return 0; } |
Данный паттерн имеет некоторые интересные свойства. Во-первых, он позволяет родительскому классу знать о дочернем на правах forward declaration, при этом никаких преобразований типов для этого делать не нужно. Во-вторых, он позволяет совершенно безопасно делать приведение вниз по иерархии обычным static_cast. В третьих, он позволяет реализовывать так называемые статические виртуальные функции (пример вызова такой функции находится в строке 19). | ||
«CRTP» имеет более сложную организацию, чем «Nonvirtual interface», поэтому, выбирая между последними, следует четко понимать возможности паттернов и ваши потребности — соответствуют ли они друг другу. |
|
Статистика |
|