【问题标题】:How does an inheritant class work in this situation ???在这种情况下继承类如何工作???
【发布时间】:2018-01-08 18:09:27
【问题描述】:
class A {
public:
    A() { foo(); }
    ~A() { foo(); }
    void foo() { cout << 3; }
    void bar() { foo(); }
};
class B : public A {
    void foo() { cout << 2; }
};
int main() {
    B b;
    b.bar();
    return 0 ;
}

我编译并运行了它。结果是 333 ...但我想:当我打电话时 b.bar() 。它将直接到 bar() 然后调用 B 类中的 foo() 函数,因为 A 类中的 foo() 在 B 类中被覆盖。我认为的结果是 323 。但是我错了。我错过了什么吗?请帮我解释一下它是如何工作的@

【问题讨论】:

  • 我想你想要一个virtual foo()
  • 我的两分钱在这里:1)即使您将 foo() 实现为虚函数,一旦在“A”构造函数中调用,它将运行 A::foo() 而不是 B::foo( ) 因为还没有创建“B”; 2)你不能在析构函数中调用任何虚函数,因为“B”可能已经被销毁并且取消引用 B::foo() 指针可能会使应用程序崩溃,或者处理已经覆盖的内存,或者其他什么。在这里我们还没有讨论虚拟继承,它会让事情变得更加棘手。

标签: c++ inheritance polymorphism


【解决方案1】:

问题是您有一个非虚拟的foo(),因此A::bar() 将调用它知道的唯一foo(),即A::foo(),即使它是调用它的B。

试试:

class A {
public:
    A() { foo(); }
    virtual ~A() { foo(); }             // <<---------- recommendation
    virtual void foo() { cout << 3; }   // <<<--------- solves it
    void bar() { foo(); }
};
class B : public A {
    void foo() override { cout << 2; }  // <<---------- recommendation
};

其他信息:

在基类中创建foo()virtual 允许每个类重写此函数,并确保调用的foo() 将是与对象的真实类对应的foo()

这是一个good practice,然后在派生类中使用关键字override:这不是强制性的,但如果您在函数签名中打错字,您会立即注意到编译时错误消息。

如果您的类中至少有一个虚函数,则另一个好的做法是使您的基类析构函数为虚函数。

最后一句话:在 B 中,foo() 的私人。这是合法的,但很奇怪,因为继承表明 B 是 A 的一种,但您不能将 B 对象完全用作 A 对象。

【讨论】:

    【解决方案2】:

    成员A::foo 是非虚拟的,因此无论在哪里使用都会被静态绑定。因此在编译A::bar 时,对foo() 的调用将(静态)绑定到实现A::foo()A::foo 中的这个静态绑定不会因为您稍后创建派生类 B 的实例而改变。 但是,如果你在 main 中调用 b.foo()B::foo 将被绑定。

    为了通过A::bar 调用B::foo,您必须将A::foo 声明为`virtual:

    class A {
    public:
        A() { foo(); }
        virtual ~A() { foo(); }
        virtual void foo() { cout << 3; }
        void bar() { foo(); }
    };
    

    请注意,您还将析构函数声明为虚拟;非虚拟析构函数很少有意义。

    【讨论】:

      【解决方案3】:

      您必须包含 virtual 才能覆盖 A 中存储的功能。

      添加到 A

      virtual void foo() { cout << 3; } 
      

      和B

      void foo() override { cout << 2; }
      

      应该做的伎俩。虚函数是成员函数,其行为可以在派生类中被覆盖。与非虚函数相反,即使没有关于类的实际类型的编译时信息,也会保留被覆盖的行为。如果派生类是使用基类的指针或引用来处理的,则对被覆盖的虚函数的调用将调用派生类中定义的行为。

      【讨论】:

        猜你喜欢
        • 2023-03-24
        • 2020-09-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-01
        • 1970-01-01
        • 2021-05-25
        相关资源
        最近更新 更多