简体   繁体   English

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

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

I'm aware that one can make implementation for pure virtual function in base class, as a default implementation. 我知道,可以将基类中的纯虚函数实现为默认实现。 But i don't quite understand the code below. 但是我不太明白下面的代码。

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();
}

Why does the B::f1() calls B::f2() instead of A::f2. 为什么B :: f1()调用B :: f2()而不是A :: f2。 I know it will behave this way, but why? 我知道它会以这种方式运行,但是为什么呢? what basic knowledge i have missed. 我错过了哪些基本知识。

another question, did implementation for pure virtual function in base class make the pure(=0) unnecessary? 另一个问题,基类中纯虚函数的实现是否使pure(= 0)不必要?

This is the behaviour the C++ standard defines for virtual functions: call the version of the most derived type available. 这是C ++标准为虚拟函数定义的行为:调用可用的最多派生类型的版本。

Sure, for normal objects, the most derived type is the one of the object itself: 当然,对于普通对象,最派生的类型是对象本身之一:

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

The interesting part is if you have pointers or references: 有趣的是,如果您有指针或引用:

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

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

The same occurs inside f1, actually, you do implicitly: f1 内部也会发生相同的情况,实际上,您隐式地这样做:

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

There's a phenomenon when this does not occur (the example below requires a copy constructor): 当不发生这种情况时会出现一种现象(以下示例需要一个复制构造函数):

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

What actually happens here is that only the A part of b is copied into a and the B part is dropped, so a actually is a true, non-derived A object. 实际发生的情况是,仅将bA部分复制到a ,而B部分被删除,因此a实际上是一个真实的,非派生的A对象。 This is called 'object slicing' and is the reason for that you cannot use base objects in eg a std::vector to store polymorphic objects, but need pointers or references instead. 这就是所谓的“对象切片”,这是您不能在std::vector使用基础对象来存储多态对象的原因,而需要指针或引用。


Back to virtual functions: If you are interested in the technical details, this is solved via virtual function tables, short vtables. 返回虚拟函数:如果您对技术细节感兴趣,可以通过虚拟函数表(简短的vtable)来解决。 Be aware that this is only a de-facto standard, C++ does not require implementation via vtables (and actually, other languages supporting polymorphism/inheritance, such as Java or Python, implement vtables, too). 请注意,这只是事实上的标准,C ++不需要通过vtables实现(实际上,其他支持多态性/继承的语言,例如Java或Python,也都实现了vtables)。

For each virtual function in a class there's an entry in its corresponding vtable. 对于类中的每个虚函数,在其对应的vtable中都有一个条目。

Normal functions are called directly (ie an unconditional branch to the function's address is executed). 普通函数被直接调用(即,执行到函数地址的无条件分支)。 For virtual function calls, in contrast, we first need to lookup the address in the vtable and only then we can jump to the address stored there. 相反,对于虚拟函数调用,我们首先需要在vtable中查找地址,然后才能跳转到存储在其中的地址。

Derived classes now copy the vtables of their base classes (so initially these contain the same addresses than the base class tables), but replace the appropriate addresses as soon as you override a function. 现在,派生类将复制其基类的vtable(因此最初它们包含的地址与基类表的地址相同),但是只要您覆盖了函数,就替换相应的地址。

By the way: You can tell the compiler not to use the vtable, but explicitly call a specific variant: 顺便说一句:您可以告诉编译器不要使用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