什么是多态?
多态,字面意思理解就是有多种形态。在C++中,多态有静态多态和动态多态两种。
静态多态:也叫静态绑定和早绑定,编译器在编译期间完成,编译器根据函数实参的类型,推断出要调用的那 个函数,如果有对应的函数就调用函数,否则出现编译错误。(有函数重载和泛指编程两种)
动态多态:也叫动态绑定和晚绑定,编译器在程序执行期间判断所引用对象的实际类型,根据其实际类型调用 相应的方法。
动态绑定的条件:
- 基类必须包含虚函数,且派生类一定要重写该虚函数(覆盖的概念)
- 通过基类的指针或引用调用虚函数
使用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;
}
模型图: