【问题标题】:dynamic_cast changes original object?dynamic_cast 改变原始对象?
【发布时间】:2015-02-03 21:11:17
【问题描述】:

为什么dynamic_cast<new>(old) 会更改old

示例代码:

#include <iostream>
#include <string>

class MyInterface {
public:
  virtual void say() = 0;  
  virtual ~MyInterface() { }
};

class SubInterface : public MyInterface {
public:
  std::string test = "test";
  virtual void say() = 0;
  virtual ~SubInterface() { }
};

class Example : public SubInterface { 
public:
  void say() {
    std::cout << test << std::endl;
  } 
}; 


int main() {
  MyInterface* ex1 = new Example(); 
  SubInterface* ex2 = dynamic_cast<SubInterface*>(ex1);
  if (ex2 != nullptr) {
    std::cout << "call ex2->say(): ";
    ex2->test = "something else";
    ex2->say();
  }
  else { 
    std::cout << "error" << std::endl;
  }

  std::cout << "call ex1->say(): ";
  ex1->say();

  std::cerr << "debug: ex1=" << ex1 << "; ex2=" << ex2 << std::endl;

  return 0;
}

哪些输出:

call ex2->say(): something else
call ex1->say(): something else
debug: ex1=0xf1e010; ex2=0xf1e010

所以我预计ex2ex1 不同,因此预计ex2-&gt;test = "something else"; 不会改变ex1。我想这是预期的行为,但为什么呢? (如果它们没有区别,为什么还要为dynamic_cast的结果分配任何东西?(可以继续使用ex1吗?))

感谢任何帮助。

【问题讨论】:

  • 您为什么希望它们有所不同?它们是指向同一个对象的两个指针,只是通过不同的接口
  • 顺便说一句,值得注意的是,即使ex1 中的原始指针值不等于ex2 中的值,它们仍然指向同一个对象。向下或向上转换对象指针可能会导致不同的内存地址,具体取决于编译器如何为层次结构中的每个类布置 vtable。 (对于多重继承尤其如此。)
  • —1:请检查您的假设写一个依赖它们是否正确的问题。

标签: c++ inheritance casting


【解决方案1】:

我猜这是预期的行为,但为什么呢?

您正在将指针转换为不同的类型,而不是创建新对象。两者都指向同一个Example 对象;一个将其视为MyInterface,另一个将其视为SubInterface。因此,在通过一个指针修改对象后,通过另一个指针可以看到对它的更改,因为两者都指向同一个对象。

如果它们没有区别,为什么还要为dynamic_cast的结果分配任何东西?

它们不一定相同。通过多重继承,不同的基类子对象可能位于完整对象内的不同位置。在这种情况下,向下转换可能必须调整指针值以指向完整的对象。

可以继续使用ex1吗?

没有。即使在您的情况下,它确实具有相同的值,但它的类型错误。它被声明指向MyInterface,它没有testmember,所以你不能说ex1-&gt;test

【讨论】:

    【解决方案2】:

    ex1 和 ex2 指向同一个对象,但类型不同。换句话说,内存是一样的(同一个 Example 对象),但是你如何操作内存是通过两个不同的接口(MyInterface 或 SubInterface)来完成的。

    dynamic_cast 是一种运行时转换,可用于通过与其他变量类型所允许的不同(相关)接口安全地操作数据。这有很多用途,尽管您的示例当然不需要它。

    【讨论】:

      【解决方案3】:

      dynamic_cast 所做的只是另外验证指向对象的实际类型是否与您期望的匹配,如果不匹配则返回nullptr。如果它们匹配,它会返回一个指向同一个对象的指针,就好像你做了一个static_cast(形象地说,除了运行时检查之外还有一些其他的细微差别)。此附加验证不会创建新对象。 dynamic_cast 没有改变对象 - 你做了。

      【讨论】:

      • 它实际上可以返回一个不同的指针值,但它指向(因此会比较等于)原始对象。
      • @cdhowie 谢谢,澄清了。
      • 谢谢。对于任何对我的意思感到困惑的人,here is an example。请注意,B 指针的值与 C 指针的值不同,但它仍然与之相等。
      【解决方案4】:

      Dynamic_cast 永远不会更改原始对象,在您的情况下为“ex1”。最初分配的内存保持不变。否则,您将遇到各种泄漏和内存损坏。

      您的意图似乎也是要了解它是否可以为您提供与输入不同的指针。

      要理解这一点,您必须从两个方向进行推理 - 向上转换和向下转换以及继承和成员变量等。

      其他人在这个问题上有很好的答案。建议搜索相关的。

      【讨论】:

        猜你喜欢
        • 2017-07-20
        • 2016-11-30
        • 2017-09-11
        • 2020-04-24
        • 2016-02-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-07
        相关资源
        最近更新 更多