纯虚函数,在C ++中实现

问题描述 投票:0回答:2

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

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。我知道它会这样,但为什么呢?我错过了什么基础知识。

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

c++ c++11
2个回答
2
投票

这是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

这里实际发生的是,只有Ab部分被复制到a并且B部分被丢弃,所以a实际上是一个真正的,非衍生的A对象。这称为“对象切片”,这是你不能在e中使用基础对象的原因。 G。用于存储多态对象的std::vector,但需要指针或引用。


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

对于类中的每个虚函数,在其对应的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

-2
投票

首先是它

void A1::f1();

void A1::f2()

因为否则这些将是自由函数而没有A的方法,

然后这些功能必须公开使用​​它们就像你做b.f1()一样

完成此操作后,您可能知道无法创建纯虚拟类,但纯虚拟方法仍然可以使用A::f1()A::f2()看到的实现。要创建继承类,必须覆盖所有纯虚方法。 B用B::f1()B::f2()做这个,所以你可以毫无问题地创建你的类,并且仍然可以使用母亲方法A::f1()的实现,即使它是纯虚拟的。

© www.soinside.com 2019 - 2024. All rights reserved.