C++多态 虚函数

什么是多态?

      多态,字面意思理解就是有多种形态。在C++中,多态有静态多态和动态多态两种。

      静态多态:也叫静态绑定和早绑定,编译器在编译期间完成,编译器根据函数实参的类型,推断出要调用的那                          数,如果有对应的函数就调用函数,否则出现编译错误。(有函数重载和泛指编程两种)

      动态多态:也叫动态绑定和晚绑定,编译器在程序执行期间判断所引用对象的实际类型,根据其实际类型调用                          相应的方法。

动态绑定的条件:

  1. 基类必须包含虚函数,且派生类一定要重写该虚函数(覆盖的概念)
  2. 通过基类的指针或引用调用虚函数    
虚函数

      使用virtual关键字修饰成员函数,该成员函数叫做虚函数。

重写(覆盖)
       不在同一作用域中(基类和派生类),函数的名字相同,参数列表相同,返回值相同(协变除外:基类返回基          的指针或引用,派生类返回派生类的指针或引用),使用关键字virtual修饰,访问权限可以不同。

纯虚函数

        在virtaual修饰的成员函数后面写上=0,则成员函数为纯虚函数。

        包含纯虚函数的类叫做抽象类,抽象类不能实例化对象,纯虚函数类必须在派生类中重新定义以后,派生类才         能实例化对象。

问题一:构造函数为什么不能是虚函数?

         构造函数的目的是创建一个类对象并初始化,而虚函数是需要一个虚表指针来调用它,虚表指针存储在类对象          的内存中,构造函数构造一个对象时,由于对象还没有创建成功,就没有分配内存的存储空间,找不着虚表              指针。

问题二:为什么静态成员函数不能是虚函数?

           static成员函数在类中没有this指针,所有类的对象共用同一段代码,没有动态绑定。

问题三: 友元函数为什么不能是虚函数?

            友元函数不能继承且不是类的成员函数。

问题四:赋值运算符重载函数是给成普通函数好,还是虚函数好呢?

            不建议给成虚函数,因为编译器会自动合成赋值运算符重载函数,给成虚函数会造成覆盖

问题五:什么情况下析构函数最好给成虚函数?

            在派生类中动态开辟一段内存空间,若要用基类的指针或引用来操作派生类时释放空间时,一定要将基类的              析构函数定义为虚函数。因为基类的指针访问派生类对象时只会访问继承自基类的那一部分,使派生类的部              分空间没有释放,造成内存泄漏。


各种虚函数的底层模型的实现:

一、普通虚函数的底层实现

class Base
{
public:
	virtual void FunTest1()
	{
		cout<<"FunTest1()"<<endl;
	}
	virtual void FunTest2()
	{
		cout<<"FunTest2()"<<endl;
	}
	virtual void FunTest3()
	{
		cout<<"FunTest3()"<<endl;
	}
	/*void FunTest4()
	{
		cout<<"FunTest4()"<<endl;
	}*/
	int _b;

};

typedef void (*pFun)();

void Print()
{
	Base b1;
	b1._b = 1;
	pFun * pf = (pFun *)(*(int *)&b1);//获取类对象的前4个字节,
	(*pf)();                          //并强制转换为函数指针类型
	++pf;//一个指针大小为4字节,向后偏移4字节
	(*pf)();
	++pf;//一个指针大小为4字节,向后偏移4字节
	(*pf)();
}
int main()
{
	//Base b;
	//b._b = 1;
	Print();
	return 0;
}
模型图:


二、虚函数的普通继承模型

  • 派生类函数体为空,没有重写和扩充

class Base
{
public:
	virtual void FunTest1()
	{
		cout<<"Base::FunTest1()"<<endl;
	}
	virtual void FunTest2()
	{
		cout<<"Base::FunTest2()"<<endl;
	}
	virtual void FunTest3()
	{
		cout<<"Base::FunTest3()"<<endl;
	}
	/*void FunTest4()
	{
		cout<<"FunTest4()"<<endl;
	}*/
	int _b;

};

class Derived:public Base//派生类函数体为空,没有重写和扩充
{};

void FunTest()
{
	Derived d;
}

int main()
{
	FunTest();
	system("pause");
	return 0;
}
模型图:


  • 派生类函数体不为空,重写基类函数但不扩充
派生类:

class Derived:public Base//派生类函数体不为空,重写基类函数但不扩充
{
public:
	virtual void FunTest1()
	{
		cout<<"Derived::FunTest1()"<<endl;
	}
	virtual void FunTest3()
	{
		cout<<"Derived::FunTest3()"<<endl;
	}
	void FunTest5()
	{
		cout<<"Derived::FunTest5()"<<endl;
	}
	int _d;
};
模型图:


  • 派生类函数体不为空,重写基类函数并扩充
class Derived:public Base//派生类函数体不为空,重写基类函数并扩充
{
public:
	virtual void FunTest4()
	{
		cout<<"Derived::FunTest4()"<<endl;
	}

	virtual void FunTest1()
	{
		cout<<"Derived::FunTest1()"<<endl;
	}
	virtual void FunTest3()
	{
		cout<<"Derived::FunTest3()"<<endl;
	}
	virtual void FunTest5()
	{
		cout<<"Derived::FunTest5()"<<endl;
	}
	
	int _d;
};
模型图:


三、多继承的虚函数

class B1
{
public:
	virtual void FunTest1()
	{
		cout<<"B1::FunTest1()"<<endl;
	}
	virtual void FunTest2()
	{
		cout<<"B1::FunTest2()"<<endl;
	}
};

class B2
{
public:
	virtual void FunTest3()
	{
		cout<<"B2::FunTest3()"<<endl;
	}
	virtual void FunTest4()
	{
		cout<<"B2::FunTest4()"<<endl;
	}
};
class C:public B1,public B2
{
	virtual void FunTest2()
	{
		cout<<"C::FunTest2()"<<endl;
	}
	virtual void FunTest3()
	{
		cout<<"C::FunTest3()"<<endl;
	}
	virtual void FunTest5()
	{
		cout<<"C::FunTest5()"<<endl;
	}
};

typedef void (*pFun)();

void Print(B1 &b)
{
	pFun * pf = (pFun *)(*(int *)&b);//获取类对象的前4个字节,
	(*pf)();                          //并强制转换为函数指针类型
	++pf;//一个指针大小为4字节,向后偏移4字节
	(*pf)();
	++pf;//一个指针大小为4字节,向后偏移4字节
	(*pf)();
}

void Print(B2 &b,int)
{
	pFun * pf = (pFun *)(*(int *)&b);//获取类对象的前4个字节,
	(*pf)();                          //并强制转换为函数指针类型
	++pf;//一个指针大小为4字节,向后偏移4字节
	(*pf)();
}


void FunTest()
{
	C c;
	Print(c);
	Print(c,0);

}

int main()
{
	FunTest();
	system("pause");
	return 0;
}
模型图:


四、虚函数的菱形继承

class A
{
public:
	virtual void FunTest0()
	{
		cout<<"A::FunTest0()"<<endl;
	}
};
class B1:public A
{
public:
	virtual void FunTest0()
	{
		cout<<"B1::Funest0()"<<endl;
	}
	virtual void FunTest1()
	{
		cout<<"B1::FunTest1()"<<endl;
	}
	virtual void FunTest2()
	{
		cout<<"B1::FunTest2()"<<endl;
	}
};

class B2:public A
{
public:
	virtual void FunTest0()
	{
		cout<<"B2::FunTest0()"<<endl;
	}
	virtual void FunTest3()
	{
		cout<<"B2::FunTest3()"<<endl;
	}
	virtual void FunTest4()
	{
		cout<<"B2::FunTest4()"<<endl;
	}
};
class C:public B1,public B2
{
	virtual void FunTest2()
	{
		cout<<"C::FunTest2()"<<endl;
	}
	virtual void FunTest3()
	{
		cout<<"C::FunTest3()"<<endl;
	}
	virtual void FunTest5()
	{
		cout<<"C::FunTest5()"<<endl;
	}
	
};

typedef void (*pFun)();

void Print(B1 &b)
{
	pFun * pf = (pFun *)(*(int *)&b);//获取类对象的前4个字节,
	(*pf)();                          //并强制转换为函数指针类型
	++pf;//一个指针大小为4字节,向后偏移4字节
	(*pf)();
	++pf;//一个指针大小为4字节,向后偏移4字节
	(*pf)();
	++pf;//一个指针大小为4字节,向后偏移4字节
	(*pf)();
}

void Print(B2 &b,int)
{
	pFun * pf = (pFun *)(*(int *)&b);//获取类对象的前4个字节,
	(*pf)();                          //并强制转换为函数指针类型
	++pf;//一个指针大小为4字节,向后偏移4字节
	(*pf)();
	++pf;//一个指针大小为4字节,向后偏移4字节
	(*pf)();
}


void FunTest()
{
	C c;
	Print(c);
	Print(c,0);

}

int main()
{
	FunTest();
	system("pause");
	return 0;
}
模型图:


五、虚函数的虚继承

class B
{
public:
	virtual void FunTest1()
	{
		cout<<"B::FunTest1()"<<endl;
	}
	virtual void FunTest2()
	{
		cout<<"B::FunTest2()"<<endl;
	}
	int _b;
};
class C:virtual public B
{
public:
	virtual void FunTest1()
	{
		cout<<"C::FunTest1()"<<endl;
	}
	virtual void FunTest3()
	{
		cout<<"C::FunTest3()"<<endl;
	}
	int _c;
};
typedef void (*pFun)();

void Print(B &b)
{
	pFun * pf = (pFun *)(*(int *)&b);//获取类对象的前4个字节,
	(*pf)();                          //并强制转换为函数指针类型
	++pf;//一个指针大小为4字节,向后偏移4字节
	++pf;//一个指针大小为4字节,向后偏移4字节
	++pf;//一个指针大小为4字节,向后偏移4字节
	(*pf)();

}


int main()
{
	C c;
	c._b = 1;
	c._c = 2;
	Print(c);

	system("pause");
	return 0;
}

class Base
{
public:
	virtual void FunTest1()=0
	{
		cout<<"Base::FunTest1()"<<endl;
	}
	int _b;
};
class D
{
public:
	virtual void FunTest1()
	{
		cout<<"d::FunTest1()"<<endl;
	}

};

int main()
{
	D b;
	return 0;
}
模型图:


六、虚函数的菱形虚拟继承

class A
{
public:
	virtual void FunTest0()
	{
		cout<<"A::FunTest0()"<<endl;
	}
	int _a;
};
class B1:virtual public A
{
public:
	virtual void FunTest0()
	{
		cout<<"B1::Funest0()"<<endl;
	}
	virtual void FunTest1()
	{
		cout<<"B1::FunTest1()"<<endl;
	}
	virtual void FunTest2()
	{
		cout<<"B1::FunTest2()"<<endl;
	}
	int _b1;
};

class B2:virtual public A
{
public:
	
	virtual void FunTest3()
	{
		cout<<"B2::FunTest3()"<<endl;
	}
	virtual void FunTest4()
	{
		cout<<"B2::FunTest4()"<<endl;
	}
public:
	int _b2;
};
class C:public B1,public B2
{
public:
	virtual void FunTest2()
	{
		cout<<"C::FunTest2()"<<endl;
	}
	virtual void FunTest3()
	{
		cout<<"C::FunTest3()"<<endl;
	}
	virtual void FunTest5()
	{
		cout<<"C::FunTest5()"<<endl;
	}
	int _c;
};


void FunTest()
{
	C c;
	c._a = 1;
	c._b1 = 2;
	c._b2 = 3;
	c._c = 4;

}

int main()
{
	FunTest();
	system("pause");
	return 0;
}
模型图:



        

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值