繁体   English   中英

具有C ++实现的纯虚函数

[英]pure virtual function with implementation in C++

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

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部分复制到a ,而B部分被删除,因此a实际上是一个真实的,非派生的A对象。 这就是所谓的“对象切片”,这是您不能在std::vector使用基础对象来存储多态对象的原因,而需要指针或引用。


返回虚拟函数:如果您对技术细节感兴趣,可以通过虚拟函数表(简短的vtable)来解决。 请注意,这只是事实上的标准,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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM