父级的子属性 - 访问权限

Child attribute from parent - access

本文关键字:访问 访问权 权限 属性      更新时间:2023-10-16

给定一个函数,参数 x 的父类 A 和类 B 从 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);
}

--编辑--

我衷心感谢您的帮助。

如果将b传递到bar()而不更改任何其他内容,则bar()只能访问其参数中的A,这个问题称为对象切片。

解决方案是通过引用或指针将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。 因此,在使用前检查它的原因。

好的防御性编码说你应该始终检查来自未知来源的指针。 尽管你可能相信这个cast会成功,而且你在编写bar((的时候可能是对的,但在生产代码中,完全有可能其他程序员会在两三年后出现并添加以下内容:

class C : public A
{
    ....
}
C c{};
bar(&c);

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

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

这个问题显示了这方面的细节。

--编辑--

作为对有关获取错误C2683: 'dynamic_cast': 'A' is not a polymorphic type的说明的回应,这个SO问题解释了原因。 该标准规定,必须至少有一个虚函数才能dynamic_cast<>工作,这就是多态性的含义。

我从来没有遇到过这个问题,因为现在对我来说,在生产代码中使所有析构函数都虚拟是一种反射操作。 为什么要使析构函数虚拟是一个完全独立的主题,我不打算在这里深入探讨。 可以说,它确实有其优势。

综上所述,解决方法是更改class A如下所示:

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

根据此链接,它应该从基础到多态类的派生指针工作,并且它确实属于 RTTI,但仍然绊倒错误。

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