多态

概念:一种形式有多种实现形态

静态多态:编译器在编译期间完成的,根据函数实参的类型(可能会进行隐式类型转换),可推断出要调用哪个函数,如果有对应的函数就调用该函数否则出现编译错误。(比如函数重载)

实现多态调动:基类必须加virtual关键字修饰,派生类可加可不加。(虚函数实现)

动态绑定条件

(1)必须是虚函数

(2)通过基类类型的引用或指针调用

 

赋值运算符重载、静态成员函数、友元函数不能定义为虚函数

友元函数、静态成员函数都没有this指针, 赋值运算符重载函数不是不能被派生类继承,而是被派生类的默认“赋值运算符重载函数”给覆盖了

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

1、重载

(1)同一作用域

(2)函数名相同/参数不同

(3)返回值可不同

2、重写(覆盖)

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

(2)函数名相同/参数相同/返回值相同(协变关系)

(3)基类类型必须有virtual关键字

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

3、重定义(隐藏)

(1)在不同作用域中(分别在基类和派生类)

(2)函数名相同

(3)在基类和派生类中只要不构成重写就是重定义

非虚拟继承

带虚函数的类

class Base
{
public:
virtual void FunTest1()
{
cout<<"Base::FunTest1()"<<endl;
}
 
virtual void FunTest2()
{
cout<<"Base::FunTest2()"<<endl;
}
 
int _data1;
};
 
int main()
{
Base b;
b._data1 = 0x01;
return 0;
}


 

Base类没有显式定义自己的构造函数,此时编译器会和成默认的构造函数,合成的构造函数中主要完成在对象头4个字节中填写虚表地址。(编译器自动定义的一个虚指针,存放虚表的地址)


注意:虚表是编译器在编译和链接完成之后就已经建立好了,在构造函数中只是将虚表的地址填写到对象的前4个字节

注意:同一个类的对象共用同一个虚表



【单继承(派生类中没有虚函数覆盖)

class Base
{
public:
virtual void FunTest1()
{cout<<"Base::FunTest1()"<<endl;}
 
virtual void FunTest2()
{cout<<"Base::FunTest2()"<<endl;}
           int _data1;
};
 
class Derive:public Base
{
public:
virtual void FunTest3()
{cout<<"Derive::FunTest3()"<<endl;}
 
virtual void FunTest4()
{cout<<"Derive::FunTest4()"<<endl;}
 int _data2;
};

wKioL1cXQYmBmELNAAA_z2Tg3QY634.png

如果派生类没有对基类的虚函数进行重写时,派生类虚表的结构先是基类的虚函数,然后再加上自己的虚函数部分,虚函数的顺序为在类中声明的顺序。


【单继承(派生类中有虚函数覆盖)

class Base
{
public:
virtual void FunTest1()
{
cout<<"Base::FunTest1()"<<endl;
}
 
virtual void FunTest2()
{
cout<<"Base::FunTest2()"<<endl;
}
 
int _data1;
};
 
class Derive:public Base
{
public:
virtual void FunTest1()
{
cout<<"Derive::FunTest1()"<<endl;
}
 
virtual void FunTest3()
{
cout<<"Derive::FunTest3()"<<endl;
}
 
virtual void FunTest4()
{
cout<<"Derive::FunTest4()"<<endl;
}
int _data2;
};
 
int main()
{
PrintVtable();
return 0;
}

wKiom1cXQRHxmurwAAA5sb0lZEk025.png

如果派生类中覆盖了基类的虚函数,派生类虚函数表的规则为:先将基类的虚表内容搬移过来,若派生类对基类中某个虚函数进行了重写,则会用派生类重写的虚函数地址替换掉虚表中相应位置的基类虚函数地址,替换完成之后将派生类自己新添加的虚函数地址按照声明的顺序添加进虚函数表


【多继承(派生类不覆盖基类虚函数)

class Base
{
public:
virtual void FunTest1()
{
cout<<"Base::FunTest1()"<<endl;
}
 
virtual void FunTest2()
{
cout<<"Base::FunTest2()"<<endl;
}
 
int _data1;
};
 
class Base1
{
public:
virtual void FunTest3()
{
cout<<"Base1::FunTest3()"<<endl;
}
 
virtual void FunTest4()
{
cout<<"Base1::FunTest4()"<<endl;
}
 
int _data2;
};
 
class Derive:public Base, public Base1
{
public:
virtual void FunTest5()
{
cout<<"Derive::FunTest5()"<<endl;
}
 
int _data3;
};
 
int main()
{
cout<<"sizeof(Derive) = "<<sizeof(Derive)<<endl;
Derive d;
d._data1 = 0x01;
d._data2 = 0x02;
d._data3 = 0x03;
PrintVtable();
return 0;
}

wKioL1cXSHeSWPK7AABFP1ARGn4880.png


【多继承(派生类覆盖基类虚函数)

class Base
{
public:
virtual void FunTest1()
{
cout<<"Base::FunTest1()"<<endl;
}
 
virtual void FunTest2()
{
cout<<"Base::FunTest2()"<<endl;
}
 
int _data1;
};
 
class Base1
{
public:
virtual void FunTest3()
{
cout<<"Base1::FunTest3()"<<endl;
}
 
virtual void FunTest4()
{
cout<<"Base1::FunTest4()"<<endl;
}
 
int _data2;
};
 
// 这次将继承列表中Base和Base1的位置互换
class Derive:public Base1, public Base
{
public:
virtual void FunTest1()
{
cout<<"Derive::FunTest1()"<<endl;
}
virtual void FunTest3()
{
cout<<"Derive::FunTest3()"<<endl;
}
virtual void FunTest5()
{
cout<<"Derive::FunTest5()"<<endl;
}
 
int _data3;
};
 
int main()
{
           PrintVtable();
return 0;
}

wKioL1cXSTixs509AABENGmcYvk308.png

虚拟继承

// 没有虚函数覆盖,但派生类有自己的虚函数
class Base
{
public:
virtual void FunTest1()
{
cout<<"Base::FunTest1()"<<endl;
}
 
virtual void FunTest2()
{
cout<<"Base::FunTest2()"<<endl;
}
 
int _data1;
};
 
class Derive:virtual public Base
{
public:
virtual void FunTest3()
{
cout<<"Derive::FunTest3()"<<endl;
}
virtual void FunTest4()
{
cout<<"Derive::FunTest4()"<<endl;
}
 
int _data2;
};

虚拟继承编译器为派生类合成的默认构造函数分析


wKiom1cXTdLxP4hOAABE6d4919Q542.png

编译器为派生类合成的默认构造函数任务分析:

wKioL1cXTrvChGl-AAF98j7Khks992.pngwKiom1cXTjbjiQcuAACp2aVZAZg475.png


虚拟继承派生类对象模型分析

wKioL1cXTwvxbFWFAAE1cVre-f0177.png