这是一个有效的向下转型

时间:2014-09-10 15:30:07

标签: c++ pointers

我有一个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;
}

由于

3 个答案:

答案 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类型的对象一样。 但是,每个编译器可能都有不同的派生类内存布局,因此在某些情况下可能有效,但不能保证。