我有一个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;
}
由于
答案 0 :(得分:4)
这是一个有效的向下转发。
是。您的演员表内部适用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
,因为它不会修改任何数据成员。答案 1 :(得分:0)
您编写的代码实际上是有效的,但我想提出一些观察结果。请注意,它仅在您传递给print
的对象是parent
或其他派生类时才有效。
然后请注意,由于您必须使用print
功能,只需更改功能签名以获取parent
而不是grand
然后更加安全你不必担心演员阵容。
然后请注意,问题的一个可能原因是,在执行转换的文件中,编译器没有看到grand
和{{1}之间的关系所以你的C风格演员会回到parent
,而不是你想要的。如果您无法更改reinterpret_cast
的签名,请至少将演员表更改为print
(或可能static_cast
,但您无法在示例中执行此操作,因为类不是多态的,所以当编译器看不到类关系时编译器将无法编译。
答案 2 :(得分:0)
如果由于某种原因编译时没有RTTI(运行时类型信息),则应该应用dynamic_cast
或至少static_cast
而不是C风格的转换。
您的C样式转换与reinterpret_cast
相同,它基本上解释了指向的内存,就好像那里构造了parent
类型的对象一样。 但是,每个编译器可能都有不同的派生类内存布局,因此在某些情况下可能有效,但不能保证。