c++ - 在 C++ 中实现的纯虚函数

标签 c++ c++11

我知道可以在基类中实现纯虚函数,作为默认实现。但是我不太明白下面的代码。

class A {
public:
    virtual void f1() = 0;
    virtual void f2() = 0;
};
void A::f1(){
    cout << "base f1" << endl;
    f2();
}
void A::f2(){
    cout << "base f2" << endl;
}

class B: public A {
public:
    void f1() { A::f1(); }
    void f2() { cout << "derived f2" << endl; }
};

int main(){
    B b;
    b.f1();
}

为什么 B::f1() 调用 B::f2() 而不是 A::f2。我知道它会这样,但为什么呢? 我错过了什么基础知识。

另一个问题,在基类中实现纯虚函数是否不需要 pure(=0)?

最佳答案

这是 C++ 标准为虚函数定义的行为:调用可用的派生类型最多的版本。

当然,对于普通对象,最派生的类型是对象本身:

B b;
b.f1(); // of course calls B's version

有趣的是,如果您有指针或引用:

B b;
A& ar = b;
A* ap = &b;

// now both times, B's version will be called
ar.f1();
ap->f1();

同样的事情发生在内部 f1,实际上,你隐含地做了:

this->f2(); // 'this' is a POINTER of type A* (or A const* in const functions).

没有出现这种情况时有一种现象(下面的例子需要拷贝构造函数):

B b;
A a = b; // notice: not a pointer or reference!
A.f1();  // now calls A's version

这里实际发生的是只有 bA 部分被复制到 aB部分被删除,所以 a 实际上是一个真实的、非派生的 A 对象。这称为“对象切片”,这就是您不能在 e 中使用基础对象的原因。 G。一个 std::vector 来存储多态对象,但需要指针或引用。


回到虚函数:如果您对技术细节感兴趣,这可以通过虚函数表(简称 vtables)来解决。请注意,这只是一个事实上的标准,C++ 不需要通过 vtables 实现(实际上,其他支持多态/继承的语言,如 Java 或 Python,也实现了 vtables)。

对于类中的每个虚函数,在其对应的 vtable 中都有一个条目。

直接调用普通函数(即执行到函数地址的无条件分支)。相比之下,对于虚函数调用,我们首先需要在 vtable 中查找地址,然后才能跳转到存储在那里的地址。

派生类现在复制它们基类的 vtable(因此最初它们包含与基类表相同的地址),但是一旦您覆盖函数就替换适当的地址。

顺便说一句:你可以告诉编译器不要使用 vtable,而是显式调用特定的变体:

B b;
A& a = b;
a.A::f1(); // calls A's version inspite of being virtual,
           // because you explicitly told so
b.A::f1(); // alike, works even on derived type

关于c++ - 在 C++ 中实现的纯虚函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54959504/

相关文章:

c++ - 如何将文件名参数设置为实际文件名

c++ - 接口(interface)类产生 "Use of undefined type"

c++ - C++ 中的 Ukkonen 算法

c++ - 冲突的不匹配标签与标准库一起编译,但不以其他方式编译

c++ - Box2D:导致 "Polygon is degenerate"的三角形

c++ - g++ (mingw) 表示 to_string 不是 std 的成员

c++ - 可变参数模板中的分支

c++ - 使 std::atomic<> 对象具有限定符 - volatile 是否有意义?

c++ - 为什么 `std::pair<int, movable>` 需要 [deleted] `const&` 复制构造函数?

c++ - 是否有自动noexcept说明符?