Si usted es capaz de cambiar el diseño clases Source, puede reemplazar totalmente el polimorfismo dinámico (que usa funciones virtuales) con el polimorfismo estático y utilizar el CRTP idiom:
template <class TDerived>
class Base
{
public:
int getSize()
{ return sizeof(TDerived); }
void print()
{
std::cout
<< static_cast<TDerived*>(this)->getSize()
<< std::endl;
}
int some_data;
};
class Derived : public Base<Derived>
{
public:
int some_other_data1;
int some_other_data2;
};
class AnotherDerived : public Base<AnotherDerived>
{
public:
int getSize()
{ return some_unusual_calculations(); }
// Note that the static_cast above is required for this override to work,
// because we are not using virtual functions
};
int main()
{
Derived d;
d.print();
AnotherDerived ad;
ad.print();
return 0;
}
Usted puede hacer esto cuando la necesaria comportamiento polimórfico del programa puede ser determinado en tiempo de compilación (como el caso sizeof
), ya que el CRTP no tiene la flexibilidad de polimorfismo dinámico para resolver el objeto deseado en tiempo de ejecución.
El polimorfismo estático también tiene la ventaja de un mayor rendimiento al eliminar la sobrecarga de llamada de función virtual.
Si no desea templatar la clase Base o necesita tener diferentes instancias derivadas de la clase Base en una misma ubicación (como una matriz o un vector), puede usar CRTP en una clase media y mover la clase polimórfica comportamiento a esa clase (similar a la Polymorphic copy construction example en la Wikipedia):
class Base
{
public:
virtual int getSize() = 0;
void print()
{
std::cout << getSize() << std:endl;
}
int some_data;
};
template <class TDerived>
class BaseCRTP: public Base
{
public:
virtual int getSize()
{ return sizeof(TDerived); }
};
class Derived : public BaseCRTP<Derived>
{
// As before ...
};
class AnotherDerived : public BaseCRTP<AnotherDerived>
{
// As before ...
// Note that although no static_cast is used in print(),
// the getSize() override still works due to virtual function.
};
Base* obj_list1[100];
obj_list1[0] = new Derived();
obj_list1[2] = new AnotherDerived();
std::vector<Base*> obj_list2;
obj_list2.push_back(new Derived());
obj_list2.push_back(new AnotherDerived());
-
actualización: ahora encontró una similar pero más detallada answer en stackOverflow que explica que si derivamos más lejos de la derivada clases anteriores (por ejemplo, class FurtherDerived : public Derived {...}
), el sizeof
no informa correctamente Él da un more complex variant del código para superar esto.
Realmente no hay forma de hacerlo sin agregar una función virtual. ¿Por qué necesitas saber el tamaño de las clases? – jmucchiello