C++ 转换会创建一个新对象吗?

标签 c++ casting

如上标题所示,我的问题只是 C++ 转换是否会创建目标类的新对象。当然,在问这个问题之前,我已经使用了 Google、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, 被销毁,因为 B 和 C 的虚拟 A 合并到 END 中的一个嵌入对象以避免歧义。由于(正如我一直认为的那样)dynamic_cast 通常只会将指针存储的地址增加嵌入式(cast 的)目标类的偏移量,因此由于目标(B 或 C)类被分为几个零件。

但如果我使用 MSVC++ 2011 Express 运行示例,一切都会按预期发生(即它会运行,所有 *.a 输出 2),指针只是略有不同。因此,我怀疑强制转换只是将源指针的地址移动了 B 的/C 的实例的内部偏移量。

但是怎么办? B/C 的结果实例如何知道共享 A 对象的位置。由于在 END 对象中只有一个 A 对象,但通常在 B 和 C 中有一个 A 对象,因此 B 或 C 中一定没有 A 的实例,但实际上,两者似乎都有 A 的实例。

或者 virtual 只将对 A 的成员的调用委托(delegate)给中央 A 对象,而不删除从 A 继承 virtual 的每个基类的相应 A 对象(即 virtual实际上并没有破坏继承对象的内部结构和因此嵌入的对象,而只是不使用它们的虚拟化(=共享)成员)?

或者 virtual 创建一个新的“偏移映射”(即告诉所有成员相对于指向类实例的指针的地址偏移的映射,我不知道实际的术语)对于这样的转换对象来处理它们的“分布式”?

我希望我已经澄清了一切,非常感谢
蓝斑

附言:
如果有一些语法错误,我很抱歉,我只是一个爱喝啤酒的巴伐利亚人,不是母语人士: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 对象。

最佳答案

my question is simply whether or not a C++ cast does create a new object of the target class.

是的,转换为类类型会创建该类型的新临时对象。

请注意,您的示例不会在任何地方转换为类:它执行的唯一转换是指针类型。这些强制转换确实会创建指针的新实例 - 但不会创建指向的对象。我不确定您的示例应该演示什么,也不确定它与您提出的问题有何关系。

此外,dynamic_cast 在您使用它的地方是不必要的;隐式转换也同样有效。

Since (as I always thought) dynamic_cast usually only increases the address stored by a pointer by the offset of the embedded (cast's) target class

你一定在想 static_cast 之类的东西。 dynamic_cast 更强大。例如,它可以从 B* 转换为 C*,即使它们在编译时是不相关的,通过向下到 END* 和然后备份另一个分支。 dynamic_cast 利用运行时类型信息。

How does the resulting instance of B / C know the position of the shared A object.

这是依赖于实现的。典型的实现会在派生类实例中保留空间以存储其虚拟基类实例的偏移量。大多数派生类的构造函数初始化所有这些偏移量。

关于C++ 转换会创建一个新对象吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18669197/

相关文章:

java.lang.ClassCastException : java.net.URI 无法转换为 java.net.URL

go - 如何在golang中将bool转换为int8

c++ visual studio 2008问题,一个解决方案中有两个项目

c++ - 这里声明了什么?

c++ - 从 C++ 中未解析的外部调用 C 函数

java - 将泛型 Collection<Object> 转换为 Collection<Integer>

c++ - COM 中的 Release() 函数

c++ - 写入纹理数组的一层并从另一层读取

ios - Swift 2 - 类型转换和可选链接

java - ClassCast 异常无法将字符串转换为 boolean 值