如上面的标题所示,我的问题是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;
}
Run Code Online (Sandbox Code Playgroud)
据我所知,B和C的实际结构,通常由A的嵌入式实例和B的变量组成.C,被破坏,因为B和C的虚拟A被合并到END中的一个嵌入对象以避免歧义.因为(我一直认为)dynamic_cast通常只会增加指针存储的地址乘以嵌入(强制转换)目标类的偏移量,因为目标(B或C)类被分成几个类,所以会出现问题部分.
但是,如果我使用MSVC++ 2011 Express运行示例,一切都会按预期发生(即它将运行,所有*.a输出2),指针只是略有不同.因此,我怀疑转换只是通过B/C实例的内部偏移来移动源指针的地址.
但是怎么样?生成的B/C实例如何知道共享A对象的位置.由于END对象中只有一个A对象,但通常是B和C中的A对象,因此B或C必须没有A的实例,但实际上两者似乎都有一个实例.
或者virtual只将对A的成员的调用委托给中央A对象而不删除从A继承虚拟的每个基类的相应A对象(即virtual实际上不破坏继承的内部结构,因此嵌入对象但不使用它们的虚拟化( =共享)成员)?
或者是否virtual创建了一个新的"偏移量图"(即地图,它告诉所有成员相对于指向类实例的指针的地址偏移量,我不知道实际的术语),这样的铸造对象能够处理它们的"分布式"吗?
我希望我已经澄清了一切,非常感谢
BlueBlobb
PS:
对不起,如果有一些语法错误,我只是一个喜欢巴伐利亚啤酒的啤酒,而不是母语:P
编辑:
如果添加了这些行来输出所有int的地址:
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";
Run Code Online (Sandbox Code Playgroud)
它们同样意味着确实只有一个A物体.
我的问题是C++强制转换是否确实创建了目标类的新对象.
是的,对类类型的强制转换将创建该类型的新临时对象.
请注意,您的示例不会在任何地方强制转换为类:它执行的唯一转换是指针类型.这些强制转换确实会创建新的指针实例 - 但不会创建指向的对象.我不确定你的例子应该展示什么,也不确定它与你陈述的问题有什么关系.
另外,dynamic_cast在你使用它的地方是不必要的; 隐式转换也可以正常工作.
因为(我一直认为)dynamic_cast通常只会增加指针存储的地址乘以嵌入(强制转换)目标类的偏移量
你一定在想static_cast什么.dynamic_cast更强大.例如,它可以转换B*为C*,即使它们在编译时不相关,也可以通过向下转换END*然后备份另一个分支.dynamic_cast利用运行时类型信息.
生成的B/C实例如何知道共享A对象的位置.
这取决于实现.典型的实现将在派生类实例中保留空间以将偏移量存储到其虚拟基类实例.派生程度最高的类的构造函数初始化所有这些偏移量.
不,你只是看到了多重继承的影响.为了将指针强制转换为不同的基类型,必须将其调整为表示该精确类型的对象部分.编译器知道指针的原始类型和结果类型,因此它可以应用必要的偏移量.为了使派生类型满足"is-a"要求,它必须具有内置的必要结构来模拟所有基类型.
有一种情况是强制转换可以创建一个新对象,当你转换为指针或引用类型以外的类型时.除非您为该类型定义了一个强制转换运算符,否则这通常是不可能的.
| 归档时间: |
|
| 查看次数: |
4294 次 |
| 最近记录: |