C++虚函数和虚表

   一直对于C++的虚函数的概念比较模糊,今天上网查资料然后把虚拟继承这一块给搞懂了,给大家分享。

   继承是C++的一大特性,继承是复用的重要手段,。通过继承一个类,继承是类型(一个类)之间的关系建模,共享父类的一些资源,但是有些数据是共享补了的,每个类都有自己要实现的东西,所以本质是不同的。

    在这里我就不再赘述继承的概念的东西,相信懂一点C++的程序员都会使用继承,但是在这里强调一下继承的赋值兼容规则

  1. 子类对象可以赋值给父类对象(切片:将子类对象中切割出父类大小的一个对象赋值给父类对象(指针))
  2. 父类对象不可以复制给子类对象。
  3. 父类的指针/引用可以指向子类对象。
  4. 子类指针/对象不可以指向父类的对象。(除非强制类型转换,但是这是不好的)。

     赋值兼容规则在虚拟继承中会使用到,所以在这里复习一下。

     虚拟继承主要指解决菱形继承的二义性问题:
     菱形继承:多个子类继承同一个基类,最后又被一个子类继承。





从对象模型我们可以看见Assistat的虚表(vTable),其实虚表有很多叫法:
  1.  VMT
  2. vftable
  3. virtual call table
  4. dispatch table
  5. vtable
 我们一般称为vtable。虚表是C++利用runtime来实现多态的工具,也就是在运行时决定到底选用的是哪一个虚表。所以,我们借助virtual关键字将函数代码地址存入vTable来躲开静态编译期,当编译器看到virtual关键字时,编译器自动跳过。

我们来看一个没有使用虚函数的代码:
#include<iostream>
using namespace std;


class Person
{
<span style="white-space:pre">	</span>public :
<span style="white-space:pre">	</span>void BuyTickets()
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>cout << " 买票" << endl;
<span style="white-space:pre">	</span>}
protected:
<span style="white-space:pre">	</span>string _name; // 姓名
};
class Student : public Person
{
<span style="white-space:pre">	</span>public :
<span style="white-space:pre">	</span>virtual void BuyTickets()
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>cout << " 买票-半价 " << endl;
<span style="white-space:pre">	</span>}
protected:
<span style="white-space:pre">	</span>int _num; //学号
};
//void Fun(Person* p)
void Fun(Person& p)
{
<span style="white-space:pre">	</span>p.BuyTickets();
} 
int main()
{
<span style="white-space:pre">	</span>Person p;
<span style="white-space:pre">	</span>Student s;
<span style="white-space:pre">	</span>Fun(p);
<span style="white-space:pre">	</span>Fun(s);
<span style="white-space:pre">	</span>return 0;
}
  
 运行程序,输出的是两个买票,说明父类和子类都是调用的父类的void BuyTickets(),因为没有使用virtual关键字修饰在静态编译期就确定了调用Person的void BuyTickets()。

然后,我们在void BuyTickets()的前面加上vitral会怎样呢:
class Person
{
	public :
	virtual void BuyTickets()
	{
		cout << " 买票" << endl;
	}
protected:
	string _name; // 姓名
};
正如你看到的输出是买票和买票-半价,这就说明多态已经成功的实现了,但是,为什么呢?????


首先,我们得先理解一下几点:
  1. 函数只要有virtual,我们就需要把它添加键入vtable。
  2. 每个类都有自己的虚表。
  3. 虚表的位置一般存放在模块的常量段中,从始至终都只有一份。
  4. 虚表里有虚函数指针,指向本类中带有virtual的函数。
虚函数指针的大小是4个字节,就本例来说虚表的大小就是4个字节,因为只有一个虚函数:


我们可以看到虽然Student继承了Person但是,Student任然有自己的虚表,并且Student重写了virtual void BuyTickets()。这就是原因。

以下是覆盖的规则:





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值