继承类如何在这种情况下工作?

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

标签: c++ inheritance polymorphism

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。但是我错了。我错过了什么吗?请帮我解释它的实际工作原理@

3 个答案:

答案 0 :(得分:3)

问题在于你有一个非虚拟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()对应的对象的真实类。

然后在派生类中使用关键字overridegood practice:它不是强制性的,但如果你在函数签名中输入拼写错误,你会立即注意到编译 - 时间错误消息。

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

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

答案 1 :(得分:0)

成员A::foo是非虚拟的,因此在任何地方都会被静态绑定。因此,在编译A::bar时,对foo()的调用将(静态地)绑定到实现A::foo()A::foo中的此静态绑定不会因您稍后创建派生类B的实例而更改。 但是,如果您在主要地方呼叫b.foo(),则B::foo将被绑定。

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

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

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

答案 2 :(得分:-1)

您必须包含虚拟以覆盖存储在A。

中的功能

添加到

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

和B

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

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