如标题所示,我的问题是:C++类型转换是否会创建目标类的新对象。当然,在询问之前我已经使用了谷歌、MSDN、IBM和stackoverflow的搜索工具,但我找不到适当的答案。
让我们考虑以下使用虚继承解决钻石问题的实现:
#include <iostream>
#include <cstdlib>
struct A
{
int a;
A(): a(2) { }
};
struct B: virtual public A
{
int b;
B(): b(7) { }
};
struct C: virtual public A
{
int c;
C(): c(1) { }
};
struct END: virtual public B, virtual public C
{
int end;
END(): end(8) { }
};
int main()
{
END *end = new END();
A *a = dynamic_cast<A*>(end);
B *b = dynamic_cast<B*>(end);
C *c = dynamic_cast<C*>(end);
std::cout << "Values of a:\na->a: " << a->a << "\n\n";
std::cout << "Values of b:\nb->a: " << b->a << "\nb->b: " << b->b << "\n\n";
std::cout << "Values of c:\nc->a: " << c->a << "\nc->c: " << c->c << "\n\n";
std::cout << "Handle of end: " << end << "\n";
std::cout << "Handle of a: " << a << "\n";
std::cout << "Handle of b: " << b << "\n";
std::cout << "Handle of c: " << c << "\n\n";
system("PAUSE");
return 0;
}
据我理解,B和C的实际结构通常包括A的嵌入式实例和B或C的变量,但为了避免不确定性,虚拟A被合并成END中的一个嵌入对象,这样B和C的实际结构被销毁了。由于(正如我一直认为的那样)dynamic_cast通常只是将指针存储的地址增加嵌入式(转换的)目标类的偏移量,所以由于目标(B或C)类分成多个部分,会出现问题。
但是,如果我使用MSVC++ 2011 Express运行该示例,一切都会按预期发生(即运行,所有*.a输出2),指针仅略有差异。因此,我怀疑这些转换仍然只是将源指针的地址移动B / C实例的内部偏移量。
但是,如何实现呢? B / C的结果实例如何知道共享的A对象的位置。由于END对象中只有一个A对象,而在B和C中通常有一个A对象,因此B或C必须没有A的实例,但实际上它们似乎都有A的实例。
或者虚拟只是将对A的成员的调用委托给一个中央A对象,而不删除每个从A继承虚拟的基类的相应A对象的内部结构(即,虚拟实际上是否不破坏继承和嵌入对象的内部结构,而只是不使用它们的虚拟化(=共享)成员)?
或者虚拟函数为这些转换对象创建一个新的“偏移映射”(即告诉所有成员相对于指向类实例的指针的地址偏移量的映射,我不知道实际术语)以处理它们的“分布性”?
希望我已经澄清了一切,非常感谢
BlueBlobb
附言:
如果有语法错误,请见谅,我只是一个爱喝啤酒的巴伐利亚人,不是母语使用者:P
编辑:
我添加了这些行来输出所有int a的地址:
std::cout << "Handle of end.a: " << &end->a << "\n";
std::cout << "Handle of a.a: " << &a->a << "\n";
std::cout << "Handle of a.b: " << &b->a << "\n";
std::cout << "Handle of a.c: " << &c->a << "\n\n";
它们是相同的,这意味着确实只有一个A对象。
virtual public
,但是对于从B和C派生的END
,则不需要。一个普通的struct END : public B, public C
就足够了。 - WhozCraigdynamic_cast
如何“知道”该做什么?”)。 - M.M