C++ 确定多态性的大小++;班

C++ 确定多态性的大小++;班,c++,polymorphism,sizeof,C++,Polymorphism,Sizeof,使用sizeof操作符,我可以确定任何类型的大小,但是如何在运行时动态确定多态类的大小呢 例如,我有一个指向动物的指针,我想得到它所指向的实际对象的大小,如果它是猫或狗,则会有所不同。除了创建一个虚拟方法Animal::size并重载它以返回每个特定类型的sizeof,是否有一种简单的方法可以做到这一点?如果您知道可能的类型集,您可以使用RTTI通过执行dynamic\u cast找到动态类型。如果没有,唯一的方法就是通过虚拟函数 或者,您可以使用typeid,这可能比dynamic_cast快

使用
sizeof
操作符,我可以确定任何类型的大小,但是如何在运行时动态确定多态类的大小呢


例如,我有一个指向
动物
的指针,我想得到它所指向的实际对象的大小,如果它是
,则会有所不同。除了创建一个虚拟方法
Animal::size
并重载它以返回每个特定类型的
sizeof
,是否有一种简单的方法可以做到这一点?

如果您知道可能的类型集,您可以使用RTTI通过执行
dynamic\u cast
找到动态类型。如果没有,唯一的方法就是通过虚拟函数

或者,您可以使用typeid,这可能比dynamic_cast快(也可以使用dynamic_cast将其转换为层次结构中的中间类型)

看起来相当糟糕:

#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' ;
}
您可以在基类中将其抽象化,这意味着如果您忘记重写此方法,这将是一个编译器错误


编辑:这自然是假设给定的任何生物,你想知道它的大小。如果你有充分的理由相信你是在与一只狗或一个狗的子类打交道(你不在乎它是不是一个子类),那么你自然可以使用dynamic_cast进行特别测试。

我不相信有人发明了type_id()如果您能够更改源类的设计,则可以将动态多态性(使用虚拟函数)完全替换为静态多态性,并使用:

--

更新:我现在发现了一个类似但更详细的stackoverflow,它解释了如果我们进一步从上面的派生类派生(例如,
class进一步派生:公共派生{…}
),则
sizeof
将无法正确报告。他给出了一系列的代码来克服这个问题。

一个稍微复杂的方法也会起作用,就是通过一个奇怪的重复模板模式来实现它

#include <iostream>

class Base {
public:
    virtual ~Base() {}
    virtual size_t getSize() = 0;
};

template <class T>
class BaseT : public Base {
public:
    size_t getSize() override { return sizeof(T); }
};

class Child : public BaseT<Child> {};

int main()
{
    std::unique_ptr<Base> child(new Child);
    std::cout << child->getSize();
}
#包括
阶级基础{
公众:
虚拟~Base(){}
虚拟大小\u t getSize()=0;
};
模板
BaseT类:公共基{
公众:
size_t getSize()重写{return sizeof(t);}
};
类子:公共BaseT{};
int main()
{
std::唯一的ptr子项(新子项);
std::cout getSize();
}

如果不添加虚拟函数,就真的没有办法做到这一点。为什么你需要知道类的大小?比看起来糟糕更糟糕的是,每次你创建一个新动物时,你都必须修改动物的大小。我非常怀疑是否有
dynamic\u cast
typeid
在引擎盖下基本上不调用相同代码的实现(使用
dynamic\u cast
将一些检查围绕该检查,这是您手动执行的)。考虑到某些系统上的RTTI(例如,涉及DLL时的Windows)归结到字符串比较,如果
dynamic\u cast
typeid
之间有任何差异,它们很可能是可以忽略的。@Michael:我提到过。如果你也要使用dynamic\u cast,你必须修改你的代码。情况会更糟:因为dynamic\u cast可以成功地转换为中间类型es(例如鹦鹉从生物到鸟),您需要更加小心地排序这些比较!正是因为这个原因,动态\u cast可以实现这一点,它可能会更糟(我读到typeid只进行一次比较,而动态\u cast实际上必须搜索继承树。)@UncleBens:你的观点是正确的。我没有想到。dynamic cast和typeid都使用字符串比较。这是必须做到的,因为在大多数情况下,它可以跨程序集边界工作。(在libs、dll等中链接)。如果你想要性能,请远离这些。
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;
}
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());
#include <iostream>

class Base {
public:
    virtual ~Base() {}
    virtual size_t getSize() = 0;
};

template <class T>
class BaseT : public Base {
public:
    size_t getSize() override { return sizeof(T); }
};

class Child : public BaseT<Child> {};

int main()
{
    std::unique_ptr<Base> child(new Child);
    std::cout << child->getSize();
}