父级的子级属性-访问

时间:2018-08-09 01:21:18

标签: c++ inheritance access

给出一个具有父类 A 和子类 B 的参数 x 的函数,该子类继承自 A ,当它是 B 对象时,如何访问 x 属性的正确方法?上面的示例如下所示。

-编辑-

class A {
}

class B : public A {
    public:
      int foo;
}

void bar(A foo_){
    cout << foo_.foo << endl;
}

int main(){
    // Previous code:
    // A a{};
    // bar(a);

    // Current code:
    B b{};  // @O'Neil: B b(); will lead to the most vexing parse problem
    bar(b);
}

-编辑-

衷心感谢您的帮助。

3 个答案:

答案 0 :(得分:0)

如果将b传递到bar()而不进行任何其他更改,则bar()只能访问其参数内的A,这是一个Object Slicing问题。

解决方案是通过引用或通过指针将b传递到bar()中,即使参数的类型为A,也可以使用dynamic_cast<>来尝试然后返回派生对象。

按如下所示进行传递:

bar(&b);

并像这样重写bar

void bar(A *foo_)
{
    B *foo_as_B = dynamic_cast<B *>(foo_);
    if (foo_as_B != nullptr)
    {
        cout << foo_as_B->foo << endl;
    }
}

然后它将起作用。

dynamic_cast<>能够将超类的指针/引用转换为子类的指针/引用,前提是该超类对象实际上最初是作为子类实例化的。它实际上比这要复杂一些,但是仅仅入门就足够了。

在指针的情况下,如果强制转换正确,则将获得有效的指针。如果无法完成转换,则指针版本将返回nullptr。因此,在使用前进行检查的原因。

良好的防御性编码要求您应始终检查来自未知来源的指针。即使您可能认为强制转换会成功完成并且在编写bar()时可能是对的,但在生产代码中,很可能其他程序员会在两三年后出现并添加以下内容:

class C : public A
{
    ....
}

C c{};
bar(&c);

此时,对nullptr的检查将使您摆脱未定义行为的恶魔。

您也可以使用引用来执行此操作,但是此处的失败情况有所不同:它引发了一个异常,您可能想捕获该异常。

This question显示了此细节。

-编辑-

为回应有关出现错误C2683: 'dynamic_cast': 'A' is not a polymorphic type的说明,this SO Question解释了原因。该标准规定,dynamic_cast<>必须至少有一个虚函数才能起作用,这就是多态的意思。

我从来没有碰过这个问题,因为对于我来说,在生产代码中使所有析构函数虚拟化是一种反思性的行动。为什么要使析构函数虚拟化的问题是一个完全独立的主题,我在这里不做深入探讨。只需说这样做确实有其优势即可。

总而言之,解决方法是更改​​class A如下:

class A
{
public:
    virtual ~A() {}
};

答案 1 :(得分:0)

根据this link,它应该已经从基类处理到多态类的派生指针,并且它确实属于RTTI,但是仍然会出错。

答案 2 :(得分:0)

该线程的最终解决方案可以找到here。感谢所有参与者。