虚机制

1、设计如下三个class A、B、C

class A{
public:
	virtual void vfunc1();
	virtual void vfunc2();
	void func1();
	void func2();
private:
	int m_data1;
	int m_data2;
}


class B:public A{
public:
	virtual void vfunc1();
	void func2();
private:
	int m_data3;
}

class C:public B{
public:
	virtual void vfunc1();
	void func2();
private:
	int m_data4;
}
//注意:这个例子有点瑕疵,不应该写子类的函数与父类重名的。

其中class A有两个non-virtual函数,两个virtual函数。classB继承自classA ,且重写了class的 第一个虚函数,且自己又多了一个成员函数,因此,它一共有5个成员函数。classC继承自classB ,并且它重新写了继承自classB的虚函数,而且自己还有一个成员函数,因此classC共有6个成员函数。

2、三个类对象的内存图

在这里插入图片描述
可以看到:

  • 子类对象中有父类的part。
  • 然而,我们可以观察到,每个对象的内存除了成员变量以外,还会多出来一个数据,这个数据便是虚指针
  • 只要一个类中有一个函数为虚函数,那么这个类的数据中一定会多出来一个隐藏的虚指针。

3、虚表

每一个含有虚函数的类会多出来一份数据,这个数据就是所谓的虚指针。而这个指针指向的是一个表格,这个表格里存储的是函数指针。这个表格的名称为虚表虚表中的函数指针指向的是虚函数。

注意:假如一个类中有3个虚函数,那么虚表中便会有4份数据,3份为虚函数的地址,最后一份为0。
在这里插入图片描述

4、继承

继承其实包括两部分:

  • 继承成员变量(继承的就是一份内存中的数据,因此每一个对象都存储一份数据。)
  • 继承函数(继承的是调用权,因此存储函数的代码仅有一份)

5、如何调用虚函数?

新建一个指向对象C的指针p,通过p便可以调用虚函数。以C语言的形式写出来如下:

(*(p->vptr)[n])(p);
(* p->vptr [n])(p);
//上述两个都行

其中,n代表第几个函数,由编译器自动确定。

6、静态绑定与动态绑定

(1)non-virtual 函数的调用:静态绑定。
  • 调用固定地址处的函数。
(2)virtual 的调用:动态绑定。
  • 通过指针找到虚表,通过虚表找到需要调用的函数。

7、静态绑定需要满足的条件

动态绑定需要满足的条件:

  • 必须通过指针调用
  • 指针必须向上转型
  • 调用一定是虚函数

只要满足这3个条件,编译器就进行动态绑定。动态绑定时,调用的函数时不确定的,要看指针p指向什么东西。

8、 虚指针、虚表、虚函数构成虚机制

上述虚指针、虚表、虚函数构成了虚机制,也就支撑起了面向对象编程的多态这一特性。

9、多态好处的举例

例如写一个画图程序,需要绘制不同的图片。通过多态机制,可以写出很好的代码。
写一个形状类,不同的形状继承自形状类。然后将每一个形状对象是使用一个形状指针指着他们。将指针放在一个容器中。那么,不同的形状对象调用画图方法时就会画出不同的图形。这非常方便。

如果使用c语言完成这样的程序设计,就需要写多个if else 语句进行形状的判断,并且当新增加形状时又要添加新的判断分支。这样的代码不太友好。

posted @ 2020-01-12 14:30  江南又一春  阅读(139)  评论(0编辑  收藏  举报