virtual函数和虚函数表vtable

example:

#include <iostream>

class B
{
public:
  virtual void bar();
  virtual void qux();
};

void B::bar()
{
  std::cout << "This is B's implementation of bar" << std::endl;
}

void B::qux()
{
  std::cout << "This is B's implementation of qux" << std::endl;
}

class C : public B
{
public:
  void bar() override;
};

void C::bar()
{
  std::cout << "This is C's implementation of bar" << std::endl;
}

Main:

B* b = new C();
b->bar();

虚函数表:
虚函数表
实际的执行过程是:b是一个class C类型的指针,则它使用C的vpointer来寻找虚函数表,也就是C的虚函数表,其中bar()的函数指针是C::bar(),所以执行结果是"This is C's implementation of bar"

如果这些同名函数都没有virtual关键字,则都会调用基类的函数。

当基类和派生类有同名函数,但没有virtual关键字时,没有重写发生:

// SameNameFunctionTest.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <string>

using namespace std;

class Base {
public:
    void test() {
        cout << "Base Test" << endl;
    }
};

class Derived : public Base {
public:
    void test() {
        cout << "Derived Test" << endl;
    }
};

int main()
{
    Derived* d = new Derived();
    d->test();

    Base* b = new Derived();
    b->test();

    return 0;
}

Output:

Derived Test
Base Test

此时完全取决于调用函数的是基类还是派生类,基类就调用基类的函数。

另一个例子:

#include <iostream>
#include <string>

using namespace std;

struct B {
    virtual void f() const {
        cout << "B::f" << endl;
    }

    void g() const {
        cout << "B::g" << endl;
    }
};

struct D : B {
    void f() const override {
        cout << "D::f" << endl;
    }

    void g(){
        cout << "D::g" << endl;
    }
};

struct DD : D {
    void f(){
        cout << "DD::f" << endl;
    }

    void g() const {
        cout << "DD:g" << endl;
    }
};

void call(const B &b) {
    b.f();
    b.g();
}

int main(int argc, char **argv) {
    B b;
    D d;
    DD dd;

    call(b);
    call(d);
    call(dd);

    b.f();
    b.g();

    d.f();
    d.g();

    dd.f();
    dd.g();

    return 0;
}

output:

B::f
B::g
D::f
B::g
D::f
B::g // call(dd) 中的 b.g(),g()不是虚函数,调用基类或者子类的函数完全由显式的对象是什么类型决定的,这里是b类型,所以B::g()被调用
B::f
B::g
D::f
D::g
DD::f
DD:g

另一个问题是如果父类中的函数调用了一个虚函数,这个虚函数同时存在于子类和父类中,那么该调用哪个函数呢?

#include <iostream>
#include <string>

using namespace std;

class Base {
public:
    virtual void f() {
        cout << "call base f()" << endl;
        g();
    }

    virtual void g() {
        cout << "call base g()" << endl;
    }
};

class Derived : public Base {
public:
    virtual void f() {
        cout << "call derived f()" << endl;
        Base::f();
    }

    virtual void g() {
        cout << "call derived g()" << endl;
    }
};

int main(int argc, char **argv) {
    
    Base *b = new Derived();

    b->f();

    return 0;
}

output:

call derived f()
call base f()
call derived g()

实际上调用了子函数中的虚函数,因为调用的对象是一个子类对象,可以理解为this指针指向一个子类对象,因此它在多态时,看到的都是子类虚函数表中的的虚函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值