sencillos - programacion orientada a objetos c++ ejemplos
CRTP para evitar el polimorfismo dinĂ¡mico (4)
Hay dos maneras.
El primero es especificando la interfaz estáticamente para la estructura de tipos:
template <class Derived>
struct base {
void foo() {
static_cast<Derived *>(this)->foo();
};
};
struct my_type : base<my_type> {
void foo(); // required to compile.
};
struct your_type : base<your_type> {
void foo(); // required to compile.
};
El segundo es evitar el uso de la expresión de referencia a base o puntero a base y hacer el cableado en tiempo de compilación. Usando la definición anterior, puede tener funciones de plantilla que se vean así:
template <class T> // T is deduced at compile-time
void bar(base<T> & obj) {
obj.foo(); // will do static dispatch
}
struct not_derived_from_base { }; // notice, not derived from base
// ...
my_type my_instance;
your_type your_instance;
not_derived_from_base invalid_instance;
bar(my_instance); // will call my_instance.foo()
bar(your_instance); // will call your_instance.foo()
bar(invalid_instance); // compile error, cannot deduce correct overload
Por lo tanto, combinar la definición de estructura / interfaz y la deducción del tipo de tiempo de compilación en sus funciones le permite realizar el envío estático en lugar del despacho dinámico. Esta es la esencia del polimorfismo estático.
¿Cómo puedo usar CRTP en C ++ para evitar la sobrecarga de las funciones de miembros virtuales?
He estado buscando discusiones decentes sobre CRTP. Técnicas para C ++ de Todd Veldhuizen es un gran recurso para esto (1.3) y muchas otras técnicas avanzadas, como plantillas de expresión.
Además, descubrí que puedes leer la mayor parte del artículo original de C ++ Gems de Coplien en los libros de Google. Tal vez ese sigue siendo el caso.
Tuve que buscar el CRTP . Sin embargo, al haber hecho eso, encontré algunas cosas sobre el Polimorfismo Estático . Sospecho que esta es la respuesta a tu pregunta.
Resulta que ATL usa este patrón bastante extensamente.
CRTP respuesta de Wikipedia tiene todo lo que necesitas. A saber:
template <class Derived> struct Base
{
void interface()
{
// ...
static_cast<Derived*>(this)->implementation();
// ...
}
static void static_func()
{
// ...
Derived::static_sub_func();
// ...
}
};
struct Derived : Base<Derived>
{
void implementation();
static void static_sub_func();
};
Aunque no sé cuánto te compra esto realmente. La sobrecarga de una llamada de función virtual es (compilador dependiente, por supuesto):
- Memoria: un puntero de función por función virtual
- Tiempo de ejecución: una llamada de puntero a función
Mientras que la sobrecarga del polimorfismo estático de CRTP es:
- Memoria: duplicación de base por instanciación de plantilla
- Runtime: una llamada de puntero a la función + lo que está haciendo static_cast