关于c ++:继承类如何在这种情况下工作?

How does an inheritant class work in this situation ???

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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。但我错了。我错过什么了吗?请帮我解释一下它是如何工作的@


问题是,你有一个非虚拟的foo(),这样A::bar()就可以调用它所知道的唯一foo(),即A::foo(),即使是b调用它。

尝试:

1
2
3
4
5
6
7
8
9
10
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()为虚拟,允许每个类重写此函数,并确保调用的foo()将是与对象的实际类相对应的foo()

在派生类中使用关键字override是一个很好的实践:它不是强制的,但是如果在函数签名中出现错误,您会立即注意到编译时错误消息。

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

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


成员A::foo是非虚拟的,因此将在任何使用位置静态绑定。因此,在编译A::bar时,对foo()的调用将(静态地)绑定到实现A::foo()上。稍后创建派生类B的实例不会改变A::foo中的静态绑定。但是,如果您在您的主机中呼叫b.foo()B::foo将受到约束。

为了通过A::bar调用B::foo,您必须声明A::foo为"虚拟:

1
2
3
4
5
6
7
class A {
public:
    A() { foo(); }
    virtual ~A() { foo(); }
    virtual void foo() { cout << 3; }
    void bar() { foo(); }
};

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


必须包含虚拟,才能覆盖存储在中的功能。

添加到

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

到B

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

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