C++虚函数与虚函数表

       C++有个玩意叫虚函数,它的样子和普通的函数基本一样,只不过在函数前面加一个virtual关键字。它是干什么用的呢?先上一段简短的代码,结合代码来代来说明,例如有一个类People:

class People{
public:
	People(string name){
		this->name = name;
	}
	virtual void showName(){
		cout << "The People's name is " << name << endl;
	}
protected:
	string name;
};

       然后有个类Student继承它:

class Student : public People{
public:
	Student(string name):People(name){
		
	}
};
       如果我创建一个People类的指针,让它指向一个Student类的对象,用该指针调用showName:

People *people = new Student("Kenney Qin");
	people->showName();

       它就会打印出:The People's name is Kenney Qin

       如果我把Student类也写一个形式和People类中一样的函数showName:

class Student : public People{
public:
	Student(string name):People(name){
		
	}
	void showName(){
		cout << "The Student's name is " << name << endl;
	}
};

       这时再运行刚才的代码,打印出来的是: The Student's name is Kenney Qin

 也就是说,它会先去看子类有没有覆盖了这个虚函数,如果覆盖了,那么就调用子类的,否则就调用基类的,这样就很方便,可以为基类的一些函数提供默认的实现,如果用户想自己去实现,那就会调用用户自己实现的,如果用户不想自己去实现,那就调用默认的。这里注意一点,必须用指针去调用函数,才能有这种效果,如果是用类的对象去调用,就不行,例如下面这样:

People people = Student("Kenney Qin");
	people.showName();
       那么它就不会调用Student里的showName,运行结果是打印出: The People's name is Kenney Qin

 虚函数是C++中实现多态性的手段,而多态性又是面向对象编程的重要特性,由此可见虚函数的重要性。既然它这么重要,我们不仅要学会如何使用,更要知道其原理,下面说说它是如何实现的。

 首先有个概念,叫“虚函数表”,它是用来记录类中所声明的虚函数的地址,不仅基类会有一张虚函数表,派生类也有一张,而且如果派生类中没有覆盖基类中的虚函数时,派生类的虚函数表中的虚函数的地址就和基类中的一样,下面来看一张图,引自《C++ Primer》:


 上图中,有两个类,Scientist类和Physicist类,每个类分别有一张虚函数表,虚函数表的地址是作为一个隐藏的成员存储在类中,这样类的指针就能找到虚函数表在哪,进而从表中找到虚函数的地址,Scientist类和Physicist类的虚函数表的地址分别是2008和2096。在Scientist类中,有两个虚函数,show_name和show_all,在Scientist类的虚函数表中就会记录这两个虚函数的地址,在上图中分别是4064和6400。而在Physicist类中,show_all覆盖了基类的虚函数show_all,并且增加了一个新的虚函数show_field,那么Physicist类的虚函数表中所记录的就是3个地址,分别是从基类中继承而来的虚函数show_name的地址,覆盖了基类中虚函数show_all的那个函数的地址(也就是Physicist类中的show_all的地址),以及show_field的地址。因此,在Physicist类中,show_name函数的地址和基类是一样的,而由于覆盖基类中的show_all虚函数,所以Physicist类中的show_all函数有一个新的地址,此时这里的show_all函数和基类中的show_all就不一样了,它们完全可以有不同的实现。图的最下面是一个调用的例子,把一个Scientist指针指向一个Physicist对象,然后用该指针调用show_all,到底是调用基类的show_all还是派生类的show_all呢?那么就去看虚函数表,是看Scientist类的虚函数表还是看Physicist类的虚函数表呢?是看Physicist类的虚函数表,为什么类?虽然指针是Scientist类,它但指向的是一个Physicist类的对象,指针本身只存储一个地址而已,类的信息都存储在Physicist类的对象那里,所以自然是Physicist类的虚函数表。因此从Physicist的成员中找到虚函数表的地址2096,然后在地址2096处找到虚函数表,从表中找到show_all函数的地址,是6820,不知道大家有没有发现,虚函数表中的虚函数是按在类中声明的顺序排下来的,先排基类,然后排派生类,如果有覆盖就直接覆盖,换成新的地址,否则就继续往后排。找到了show_all函数的地址6820后,就可以跳到这个地址去执行这个函数了~




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值