这是有效的下投吗?

Is this a valid downcasting

本文关键字:有效      更新时间:2023-10-16

我有一个 cpp 代码,其中类 c 派生自类 b,类 b 派生自类 a。

现在 B 类有一些公共数据成员。所以我正在堆上创建一个类 c 的实例,将其指针作为指向 a 的指针传递给另一个类,在那里它向下转换指向类 b 指针的指针,然后打印类 b 的公共变量。

这是有效的下投吗?我问是因为编译器的更改破坏了这个工作代码。

我在下面包含代码片段,这些代码片段捕获了我遇到的问题。

#include <iostream>
using namespace std;

class grand
{
};
class parent : public grand
{
    public : parent(){i=0;}
    int i;
    parent(int j){ i = j;}
    void set(int j){i = j;}
};
class child : public parent{

public: child(){};
};
void print ( grand* ptr)
{
    parent *p = (parent*) ptr;
    std::cout << std::endl << p->i << std::endl;
}
int main() {
    // your code goes here
    child c;
    c.set(9);
    print(&c);
    return 0;
}

谢谢

这是有效的下投吗?

是的。您的演员表内部应用 static_cast ,根据 §5.2.9/11,这将为您提供正确的结果。如果 ptr 的参数不指向parent,则强制转换的结果是未定义的 - 以下代码的执行也是如此。

通过dynamic_cast对C++作品中的多态类型进行下铸 .上面的grand类不是多态的 - 您必须至少添加一个虚拟析构函数来grand才能使其成为多态的。否则,你将收到包含以下代码的编译器错误。

parent *p = dynamic_cast<parent*>(ptr); // Once grand is polymorphic...

并检查结果 p 是否为非零。只有这种方法才能(在运行时(显示演员表是否有效!所有其他值要么调用未定义的行为,要么调用未定义的非零值。

一些注意事项:

  • 向下抛弃几乎总是设计不佳的标志。如果可能的话,避免使用,例如使用虚拟(打印(功能。
  • print应该采用指向const的指针,因为它不会修改任何数据成员。

你的代码,正如所写的,实际上是有效的,但我想做一堆观察。请注意,它之所以有效,只是因为传递给print的对象是parent或进一步派生的类。

然后请注意,由于您必须将其转换为print函数,因此只需更改函数签名以采用parent而不是grand要安全得多,然后您不必担心转换。

然后请注意,问题的一个可能原因是,在执行强制转换的文件中,编译器看不到grandparent之间的关系,因此 C 样式强制转换回退到reinterpret_cast这不是您想要的。如果无法更改print的签名,请至少将强制转换更改为 static_cast(或可能更改为 dynamic_cast ,但不能在示例中执行此操作,因为类不是多态的(,以便编译器在看不到类关系时将无法编译。

如果出于某种原因在没有 RTTI(运行时类型信息(的情况下进行编译,则应应用 dynamic_cast 或至少应用static_cast,而不是 C 样式转换。

你的C型强制转换与reinterpret_cast相同,它基本上解释指向的内存,就好像在那里构造了一个parent类型的对象一样。但是,每个编译器可能具有不同的派生类内存布局,因此在某些情况下可能有效,但不能保证。