多态
1.静态多态
静态多态(早绑定):编译器在编译期间完成的,编译器根据函数实参的类型(可能会出现隐式类型转换),可推断出要调用的那个函数,如果有对应的函数就调用该函数,否则出现编译错误。
2.动态多态
动态多态(晚绑定):在程序执行期间(非编译期间)判断所引用对象的实际类型,根据其实际类型调相应的方法。 使用virtual关键字修饰类的成员函数时,指明该函数为虚函数,派生类需要重新实现。编译器将实现动态绑定。
动态绑定条件
必须是虚函数。通过基类类的引用或者指针调用虚函数。
注意
这里是列表文本构造函数不能用virtual修饰。(对象还未构造,如何查虚表)static和virtual不能一起用。(静态函数没有this指针)赋值运算符重载可以用virtual修饰,但不建议定义为虚函数。(在派生类和基类的赋值时可能会有问题) 友元函数不能用virtual修饰。(友元不能传递)析构函数可以用virtual修饰。(当类内有虚函数时,最好把析构函数给成虚函数。或者派生类中有申请空间并释放空间的动作时,也给成虚函数)
纯虚函数
在成员函数的形参后面写上=0,则成员函数为纯虚函数。包含纯虚函数的类叫做抽象类(也叫接口类),抽象类不能实例化出对象。纯虚函数在派生类中重新定义以后,派生类才能实现实例化出对象。
总结
派生类重写基类的虚函数实现多态,要求函数名、参数列表、返回值完全相同(协变除外)基类中定义了虚函数,在派生类中该函数始终保持虚函数的特性。只有类的非静态成员函数才能定义为虚函数,静态成员函数不能定义为虚函数。如果在类外定义虚函数,只能在声明函数时加virtual关键字,定义时不用加。构造函数不能定义为虚函数,虽然可以将赋值运算符重载函数定义为虚函数,但最好不要这么做,使用时容易混淆。不要在构造函数和析构函数中调用虚函数,在构造函数和析构函数中,对象是不完整的,可能会出现未定义的行为。最好将基类的析构函数声明为虚函数。(析构函数比较特殊,因为派生类的析构函数跟基类的析构函数名称不一样,但是构成覆盖,这里编译器做了特殊处理)虚表是所有类对象实例公有的。
虚表剖析
对于有虚函数的类,编译器都会维护一张虚表,对象的前四个字节就是指向虚表的指针。 没有覆盖
class CBase
{
public:
CBase(){m_iTest =
10;}
virtual void FunTest0(){
cout<<
"CBase::FunTest0()";}
virtual void FunTest1(){
cout<<
"CBase::FunTest1()";}
virtual void FunTest2(){
cout<<
"CBase::FunTest2()";}
private:
int m_iTest;
};
class CDerived:
public CBase {
public:
virtual void FunTest4(){
cout<<
"CDerived::FunTest4()";}
virtual void FunTest5(){
cout<<
"CDerived::FunTest5()";}
virtual void FunTest6(){
cout<<
"CDerived::FunTest6()";}
};
typedef void (*FUN_TEST)();
void FunTest()
{
CBase base;
cout<<
"CBase vfptr:"<<endl;
for (
int iIdx =
0; iIdx <
3; ++iIdx)
{
FUN_TEST funTest = (FUN_TEST)(*((
int*)*(
int *)&base + iIdx));
funTest();
cout<<
": "<<(
int *)funTest<<endl;
}
cout<<endl;
CDerived derived;
cout<<
"CDerived vfptr:"<<endl;
for (
int iIdx =
0; iIdx <
6; ++iIdx)
{
FUN_TEST funTest = (FUN_TEST)(*((
int*)*(
int *)&derived + iIdx));
funTest();
cout<<
": "<<(
int *)funTest<<endl;
}
}
int main()
{
FunTest();
return 0;
}
基类中的构造函数:填写虚表 派生类:
先拷贝基类虚表。若有重写,替换(覆盖)相同位置的函数。后面添加自己特有的虚函数。 虚函数调用:先找到虚表,从表中找到调用的函数。
有覆盖
class CBase {
public:
virtual void FunTest0(){
cout<<
"CBase::FunTest0()"<<endl;}
virtual void FunTest1(){
cout<<
"CBase::FunTest1()"<<endl;}
virtual void FunTest2(){
cout<<
"CBase::FunTest2()"<<endl;}
virtual void FunTest3(){
cout<<
"CBase::FunTest3()"<<endl;}
};
class CDerived:
public CBase
{
public:
virtual void FunTest0(){
cout<<
"CDerived::FunTest0()" <<endl;}
virtual void FunTest1(){
cout<<
"CDerived::FunTest1()" <<endl;}
virtual void FunTest4(){
cout<<
"CDerived::FunTest4()" <<endl;}
virtual void FunTest5(){
cout<<
"CDerived::FunTest5()" <<endl;}
};
typedef void (*_pFunTest)();
void FunTest()
{
CBase base;
for (
int iIdx =
0; iIdx <
4; ++iIdx)
{
_pFunTest pFunTest = (_pFunTest)(*((
int*)*(
int *)&base + iIdx));
pFunTest();
}
cout<<endl;
CDerived derived;
for (
int iIdx =
0; iIdx <
6; ++iIdx)
{
_pFunTest pFunTest = (_pFunTest)(*((
int*)*(
int *)&derived + iIdx));
pFunTest();
}
}
void TestVirtual()
{
CBase base0;
CDerived derived;
CBase& base1 = derived;
}
int main()
{
FunTest();
TestVirtual();
return 0;
}
多重继承:没有虚函数覆盖
class CBase0 {
public:
CBase0(){m_iTest =
0xB0;}
virtual void PrintB0(){
cout<<
"m_iTest = "<<hex<<m_iTest<<
" CBase0::PrintB0()" <<endl;}
int m_iTest;
};
class CBase1 {
public:
CBase1(){m_iTest =
0xB1;}
virtual void PrintB1(){
cout<<
"m_iTest = "<<hex<<m_iTest<<
" CBase1::PrintB1()" <<endl;}
int m_iTest;
};
class CBase2 {
public:
CBase2(){m_iTest =
0xB2;}
virtual void PrintB2(){
cout<<
"m_iTest = "<<hex<<m_iTest<<
" CBase2::PrintB2()" <<endl;}
int m_iTest;
};
class CDerived:
public CBase0,
public CBase1,
public CBase2
{
public:
CDerived(){m_iTest =
0xD0;}
virtual void PrintD(){
cout<<
"m_iTest = "<<hex<<m_iTest<<
" CDerived::PrintD()"<<endl;}
int m_iTest;
};
typedef void (*VFTABLE_FUN)();
void PrintVfPTab(char * _pStr, int *_pVfAddr)
{
cout<<_pStr<<endl;
for (
int iIdx =
0; ;iIdx++)
{
VFTABLE_FUN pPrintVTab = (VFTABLE_FUN)(*(_pVfAddr + iIdx));
if (NULL == pPrintVTab)
{
break;
}
pPrintVTab();
cout<<(
int*)pPrintVTab<<endl;
}
cout<<endl;
}
void FunTest() {
CDerived derived;
cout<<
sizeof(derived)<<endl;
int *pVfTAddr = NULL;
CBase0& base0 = derived;
pVfTAddr = (
int*)(*(
int *)&base0);
PrintVfPTab(
"CBase0 virtual Tab:", pVfTAddr);
CBase1& base1 = derived;
pVfTAddr = (
int*)(*(
int *)&base1);
PrintVfPTab(
"CBase1 virtual Tab:", pVfTAddr);
CBase2& base2 = derived;
pVfTAddr = (
int*)(*(
int *)&base2);
PrintVfPTab(
"CBase2 virtual Tab:", pVfTAddr);
pVfTAddr = (
int*)(*(
int *)&derived);
PrintVfPTab(
"CDerived virtual Tab:" , pVfTAddr);
derived.PrintB0();
derived.PrintB1();
derived.PrintB2();
derived.PrintD();
}
多重继承:有虚函数覆盖
class CBase0 {
public:
CBase0(){m_iTest =
0xA0;}
virtual void Print(){
cout<<
"m_iTest = "<<hex<<m_iTest<<
" CBase2::Print()"<<endl;}
int m_iTest;
};
class CBase1 {
public:
CBase1(){m_iTest =
0xB0;}
virtual void Print(){
cout<<
"m_iTest = "<<hex<<m_iTest<<
" CBase2::Print()"<<endl;}
int m_iTest;
};
class CBase2
{
public:
CBase2(){m_iTest =
0xC0;}
virtual void Print(){
cout<<
"m_iTest = "<<hex<<m_iTest<<
" CBase2::Print()"<<endl;}
int m_iTest;
};
class CDerived:
public CBase0,
public CBase1,
public CBase2
{
public:
CDerived(){m_iTest =
0xD0;}
virtual void Print(){
cout<<
"m_iTest = "<<hex<<m_iTest<<
" CDerived::Print()"<<endl;}
int m_iTest;
};
void FunTest() {
CDerived derived;
cout<<
sizeof(derived)<<endl;
CBase0& base0 = derived;
base0.Print();
CBase1& base1 = derived;
base1.Print();
CBase2& base2 = derived;
base2.Print();
derived.Print();
}
若有多个虚表,则自己的虚拟函数加在第一个虚表的末尾。
转载请注明原文地址: https://ju.6miu.com/read-676186.html