Wenn Sie in der Lage sind zu Quellenklassen Design zu ändern, können Sie völlig dynamischen Polymorphismus ersetzen (die virtuellen Funktionen verwendet die) mit statischem Polymorphismus und verwenden 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;
}
Sie können dies tun, wenn das benötigte polymorphe Verhalten von Programm kann bei der Kompilierung-Zeit (wie der sizeof
Fall) bestimmt werden, da die CRTP nicht die Flexibilität hat, von dynamischem Polymorphismus um das gewünschte Objekt zur Laufzeit aufzulösen.
Der statische Polymorphismus hat auch den Vorteil einer höheren Leistung, da der Overhead für virtuelle Funktionsaufrufe entfällt.
Wenn Sie die Basisklasse nicht templatisieren möchten oder unterschiedliche abgeleitete Instanzen der Basisklasse am selben Speicherort (wie ein Array oder ein Vektor) speichern möchten, können Sie CRTP für eine Mittelklasse verwenden und die polymorphe Komponente verschieben Verhalten dieser Klasse (ähnlich dem Polymorphic copy construction example in der 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());
-
Update: ich fand jetzt eine ähnliche, aber detailliertere answer auf Stackoverflow was erklärt, dass, wenn wir weiter von der abgeleiteten ableiten Klassen oben (zB class FurtherDerived : public Derived {...}
), wird die sizeof
nicht richtig berichten. Er gibt eine more complex variant des Codes, um dies zu überwinden.
Es gibt wirklich nicht, es zu tun, ohne eine virtuelle Funktion hinzuzufügen. Warum musst du die Größe der Klassen wissen? – jmucchiello