Frage

den sizeof-Operator, kann ich die Größe von jeder Art bestimmen - aber wie kann ich dynamisch die Größe einer polymorphen Klasse zur Laufzeit bestimmen?

Zum Beispiel habe ich einen Zeiger auf einen Animal, und ich mag die Größe des tatsächlichen Objekts, um es zeigt auf, was anders sein wird, wenn es ein Cat oder ein Dog ist. Gibt es eine einfache Möglichkeit, dies, kurz die Schaffung eine virtuelle Methode Animal::size und Überlastung es zurückzukehren, um die sizeof jeden bestimmten Typen zu tun?

War es hilfreich?

Lösung

Wenn Sie die Menge der möglichen Arten kennen, können Sie RTTI verwenden den dynamischen Typ dynamic_cast indem herauszufinden. Wenn Sie dies nicht tun, ist der einzige Weg, durch eine virtuelle Funktion.

Andere Tipps

Sie können auch typeid verwenden, die schneller als dynamic_cast sein könnte (auch mit dynamic_cast Sie Intermediär-Typen in der Hierarchie werfen können).

Es sieht eher schlecht:

#include <iostream>
#include <typeinfo>

class Creature
{
    char x[4];
public:
    virtual ~Creature() {}
};

class Animal: public Creature { char x[8];};

class Bird: public Creature { char x[16]; };

class Dog: public Animal { char x[32]; };

class Cat: public Animal { char x[64]; };

class Parrot: public Bird { char x[128]; };

unsigned creature_size(const Creature& cr)
{
    if (typeid(cr) == typeid(Animal)) {
        return sizeof (Animal);
    }
    else if (typeid(cr) == typeid(Dog)) {
        return sizeof(Dog);
    }
    else if (typeid(cr) == typeid(Cat)) {
        return sizeof(Cat);
    }
    else if (typeid(cr) == typeid(Bird)) {
        return sizeof(Bird);
    }
    else if (typeid(cr) == typeid(Parrot)) {
        return sizeof(Parrot);
    }
    else if (typeid(cr) == typeid(Creature)){
        return sizeof(Creature);
    }
    assert(false && "creature_size not implemented for this type");
    return 0;
}

int main()
{
    std::cout << creature_size(Creature()) << '\n'
    << creature_size(Animal()) << '\n'
    << creature_size(Bird()) << '\n'
    << creature_size(Dog()) << '\n'
    << creature_size(Cat()) << '\n'
    << creature_size(Parrot()) << '\n' ;
}

Für jeden neuen Typ Sie Code in die creature_size Funktion hinzufügen müssen. als auch mit einer virtuellen Größe Funktion müssen Sie diese Funktion in jeder Klasse implementieren. Allerdings wird diese Funktion wesentlich einfacher sein (perfekt Copy-n-pasteable, die es zeigt, könnte sowohl eine Einschränkung in der Sprache und ein Problem mit dem Code-Design sein):

virtual unsigned size() const { return sizeof(*this); }

Und Sie können es in der Basisklasse abstrakt machen, was bedeutet, dass es ein Compiler-Fehler sein, wenn Sie vergessen, diese Methode außer Kraft zu setzen.

Edit: dies natürlich davon aus, dass jede Kreatur Sie seine Größe wissen wollen gegeben. Wenn Sie einen starken Grund zu der Annahme haben, dass Sie mit einem Hund zu tun - oder eine Unterklasse von Dog (und Sie mich nicht, wenn es sich um eine Unterklasse), dann natürlich können Sie dynamic_cast für eine ad hoc verwenden Test.

Wenn Sie in der Lage sind Design Quellenklassen zu ändern, können Sie völlig ersetzen dynamischen Polymorphismus (die virtuellen Funktionen verwendet) mit statischem Polymorphismus und verwenden Sie die 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 des dynamischen Polymorphismus hat das gewünschte Objekt zu lösen zur Laufzeit.

Der statische Polymorphismus hat auch den Vorteil einer höheren Leistung von virtuellem Funktionsaufruf über Kopf entfernt wird.

Wenn Sie nicht wollen, Basisklasse templatize oder Sie müssen unterschiedliche abgeleitete Instanzen von Basisklasse in einer gleichen Position halten (wie ein Array oder einen Vektor), können Sie CRTP auf einem Mittelklasse verwenden und das polymorphe Verhalten bewegen zu dieser Klasse (ähnlich den Polymorphe Kopie Konstruktionsbeispiel ):

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 auf Stackoverflow beantworten, die, wenn wir erklärt weiter ergeben sich aus den abgeleiteten Klassen oben (zB class FurtherDerived : public Derived {...}), wird die sizeof nicht korrekt melden. Er gibt eine komplexere Variante des Codes, dies zu überwinden.

Ich kann nicht glauben, dass jemand type_id erfunden hat () statt richtigen Züge der Umsetzung ....

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top