C++ 多态&虚函数表 总结

首先我们来简单介绍下多态,多态顾名思义是多种形态的意思。在C++中多态又分为静态多态和动态多态。静态多态中包括重载和泛型编程,是在编译期间完成,编译器根据实参类型(可能会隐式类型转化)确定调那个函数。应注意:宏替换是在预处理期间完成所以不是静态多态。而动态多态是虚函数的调用,编译器在执行期间判断所引用对象的实际类型。

动态绑定的条件:

1.基类必须是虚函数并且在派生类中重写

2.通过基类的指针或引用调用虚函数。

继承体系同名成员函数的关系:

1.重载:在同一作用域中,函数名相同,参数列表不同,返回值可以不同。

2.重写(覆盖):

(1)不在同一作用域(基类和派生类)

(2)函数原型一模一样(函数名,参数,返回值(协变除外))

(3)基类必须是虚函数

(4)访问修饰符可以不同

几点注意:

(1)构造函数不能作为虚函数。因为虚函数是通过对象调用,而对象还没有创建完整虚表地址就无法填入因而就不能调虚函数。

(2)静态成员函数不能作为虚函数,因为虚函数通过对象拿到虚表地址,而静态成员不属于任何对象。

(3)赋值运算写成非虚函数比较好。因为赋值运算本来就是同类型赋值,如果写成虚函数对象多开辟四个字节浪费空间和时间。

(4)友元函数不是类的成员函数因此无法拿到虚表指针。也不能作为虚函数。

(5)析构函数最好给成虚函数,可以先看下面的代码

class B
{
public:
	~B()
	{
		cout<<"~B()"<

这段代码运行结果是调用了基类析构函数~B(),这样做会使D类空间没有释放,会导致内存泄漏,所以析构函数一般给成虚函数。

(6)如果在类外定义虚函数,只能在声明函数时加virtual关键字,定义时不用加。

(7)不要在构造函数和析构函数中调用虚函数,在构造函数和析构函数中,对象是不完整的,可能会出现未定义的行为。

纯虚函数:在成员函数的形参列表后面写上=0,则成员函数为纯虚函数。包含纯虚函数的类叫做抽象类(也叫接口类),抽象类不能实例化出对象。纯虚函数在派生类中重新定义以后,派生类才能实例化出对象。下面给出一个例子

class Base
{
public:
	virtual void FunTest()=0;//纯虚函数
};

class Derived:public Base
{
public:
	virtual void FunTest()
	{

	}//重定义之后派生类就成为普通的类而不是抽象类
};
int main()
{
	//Base b;
	Derived d;
	return 0;
}
虚表剖析:

class Base
{
public:
	virtual void FunTest1()
	{
		cout<<"B::FunTest1()"<

C++ 多态&虚函数表 总结_第1张图片

上面这个图是Base类的对象模型,在Base类中多了四个字节,里面存放了一个虚表指针,指向一个虚函数表,表中存放了虚函数的地址。

下面是一个我们容易出错的小问题:

        Base* pb = new Base;
	pb->FunTest1();
	pb = (Base*)new Derived;//与强转无关只和当前指向对象有关
	pb->FunTest1();
下面再来看一段程序:
class Base
{
public:
	virtual void FunTest1()
	{
		cout<<"B::FunTest1()"<
C++ 多态&虚函数表 总结_第2张图片
根据上面的一些验证我们可以知道:

虚表形成:

基类:和虚函数在基类中出现次序一致。

派生类:先拿一份基类虚函数(派生类重写了就替换基类的)新加的出现在基类虚函数后边。

总结:

多态调用(必须是虚函数)

1.取虚表指针

2.取该虚函数在虚表中的偏移量

3.调用虚函数


你可能感兴趣的:(C++,c++,多态,虚函数,总结)