C++ 使用';静态#u铸造';在C++;

C++ 使用';静态#u铸造';在C++;,c++,C++,考虑: class base { base(); virtual void func(); } class derived : public base { derived(); void func(); void func_d(); int a; } main { base *b = new base(); sizeof(*b); // Gives 4. derived * d = static_cast<der

考虑:

class base
{
    base();
    virtual void func();
}

class derived : public base
{
    derived();
    void func();
    void func_d();
    int a;
}


main
{
    base *b = new base();
    sizeof(*b); // Gives 4.
    derived * d = static_cast<derived*>(b);
    sizeof(*d); // Gives 8- means whole derived obj size..why?
    d->func_d();
}
类基
{
base();
虚void func();
}
派生类:公共基
{
派生();
void func();
void func_d();
INTA;
}
主要的
{
base*b=新的base();
sizeof(*b);//给出4。
导出*d=静态_转换(b);
sizeof(*d);//给出8-表示整个派生对象的大小。为什么?
d->func_d();
}

在上面的代码中,我向下转换了一个指向派生类指针的基对象的基指针。我想知道派生指针如何包含整个派生类对象。我可以调用派生类函数(仅在派生类中声明)。我在这里没有得到这个概念。

sizeof
在编译时存在。它既不知道也不关心在运行时,您的基本对象没有指向
派生的
。您试图用运行时变量影响编译时行为,这从根本上说是不可能的。

使用
static\u cast
将对象强制转换为它实际上没有的类型会产生未定义的行为。UB的症状差异很大。没有任何东西表明UB不能成功调用派生成员函数(但是没有任何东西保证它会成功,所以不要指望它)

<>这里是使用 StasyCase> <代码>的下拉规则,在C++标准(C++ 0x措辞)中的5.2.9(<代码> [Exp.static .Case] < /C>)中找到:

如果存在从“指向
D
的指针”到“指向
B
的指针”的有效标准转换,则可以将类型为“指向cv1
B
的指针”的PR值转换为类型为“指向cv2
D
”的PR值,其中
D
是从
B
派生的类,cv2是与cv1相同或大于cv1的cv资格,并且
B
既不是
D
的虚拟基类,也不是
D
的虚拟基类的基类。空指针值将转换为目标类型的空指针值。如果“指向cv1
B的指针”类型的PRV值指向
对于实际上是类型为
D
的对象的子对象的
B
,结果指针指向封闭对象 类型为
D
。否则,强制转换的结果是未定义的


执行运行时检查的唯一强制转换是
dynamic\u cast()
。如果在运行时强制转换可能不起作用,则应使用此强制转换

因此,从叶->根(向上投射)
static\u cast()
效果很好。

但是从根->叶(向下转换)进行转换是危险的,而且(在我看来)应该始终使用
dynamic\u cast()
来完成,因为它依赖于运行时信息。成本很低,但总值得为安全性付出代价。

请努力发布可编译代码。应该注意的是,
动态强制转换
静态强制转换
更安全,只有在基类定义了虚函数的情况下。@Ben:如果你向下强制转换,如果类型不是多态的,则是编译时错误(如果有虚拟函数),如果你正在向上抛出,那么它是安全的,因为它相当于静态映射。这意味着<代码> DyrimixCase不能完全取代<代码> StistalCase,正如你的答案似乎暗示的那样。(甚至不是所有的下拉,考虑CRTP)。@Ben:这意味着你不能得到一个编译时错误。这也意味着(但不能确认)你的类首先应该是多态的。我认为编译时错误没有什么坏处。它比运行时UB更好。如果你正在向下转换,你的设计可能有问题(或者它是需要指出的东西(动态的_cast让它突出了))。无论哪种方式,dynamic_cast都会使设计更安全;无论是编译时错误还是易于发现的运行时检查。因此,是的,这是可以做到的。是的,这是一个针对您有经验的人的优化。初学者应该安全驾驶,系好安全带,直到他们得到专家审查的代码,专家说是的,这是一个可以驾驶的地方系好安全带,因为我(专家)我已经检查过你不理解的异常情况。我不理解,不管类型转换如何,这难道不应该工作吗?我的意思是,派生类可能有其父类不知道的方法和数据成员,那么为什么向下转换不会抛出错误呢?@Cupidvogel:因为未定义的行为不会意思是“保证抛出异常,或以任何方式产生错误”。UB表示根本没有保证。哦,好吧,所以你是说,即使我们从指向基类的指针调用派生类中声明的方法(重新解释为派生类),编译器无法检测到这一点,任何异常都会在运行时被捕获?@Cupidvogel您现在可能已经知道了,但是对于选中的强制转换,您可以使用
dynamic_cast
,它允许检测不匹配(通过为引用类型引发异常或为指针类型返回空指针)。不会尝试查找对象的实际大小,即遍历对象的所有位并确定大小,而不是假设关联对象类的大小(此对象属于类D,包含2个整数,一个浮点和一个双精度,其大小必须为…)。如果它是第一个,它应该看到,即使它是
D
类型,它也没有任何与方法
func\u D
相关的空间,因此不应该计算它的存储,因为它不在那里。@AttitudeMonger您的问题是什么?一个类的所有实例都共享相同的大小。
sizeof
计算为编译时constat,不是运行时的“度量”。成员函数不会占用类实例中的空间。虚拟指针可能会占用空间,这就是
sizeof