技术交流QQ群:1027579432,欢迎你的加入!
1.C++中的多态
-
多态: 同一个事物在不同场景下的多种形态
多态分类.png
2.静态多态
- 函数重载就是一个简单的静态多态,如下面的例子:
// 静态多态 int Add(int a, int b){ return a+b; } double Add(double a, int b){ return a+b; } int main(){ Add(10, 20); Add(10.0, 20); return 0; }
- 总结:静态多态是编译器在编译期间完成的,编译器会根据实参类型来选择调用合适的函数,如果有合适的函数可以调用就调,没有的话就会发出警告或者报错。
3.动态多态
- 动态多态: 它是在程序运行时根据基类的引用(指针)指向的对象来确定自己具体该调用哪一个类的虚函数,见下面的例子:
// 动态多态 class TakeBus{ public: void TakeBusToSubway(){ cout << "go to subway\n"; } void TakeBusToStation(){ cout << "go to station\n"; } }; class Bus{ public: virtual void TakeBusToSomewhere(TakeBus& tb) = 0; // 纯虚函数,Bus是个抽象类,提供一个接口 }; class Subway: public Bus{ public: virtual void TakeBusToSomewhere(TakeBus& tb){ // 虚函数 tb.TakeBusToSubway(); } }; class Station: public Bus{ public: virtual void TakeBusToSomewhere(TakeBus& tb){ // 虚函数 tb.TakeBusToStation(); } }; int main(){ TakeBus tb; Bus *b = NULL; for(int i = 1; i <= 10; ++i){ if((rand() % i) & 1) b = new Subway(); else b = new Station(); } b->TakeBusToSomewhere(tb); delete b; return 0; }
- 从上面的例子还发现在每一个函数前都加了virtual这个虚拟关键字,它是在程序运行时根据条件去选择调用哪一个函数,参加下面的例子:
// 动态多态2 // 基类 class Base{ public: virtual void fun(int i){ // fun在基类中被声明是虚函数,可以动态绑定,根据传入的派生类对象进行调用对应的成员函数 cout << "Base::fun()\n"; } void fun1(int i){ // fun1在基类中没有被声明是虚函数,不能动态绑定 cout << "Base::fun1()\n"; } }; class Derived: public Base{ public: virtual void fun(int i){ cout << "Derived::fun()\n"; } virtual void fun1(int i){ cout << "Derived::fun1()\n"; } void fun2(int i){ cout << "Derived::fun2()\n"; } }; // 全局函数 void TestVirtual(Base& b){ b.fun(0); b.fun1(1); } int main(){ Base b1; Derived d1; TestVirtual(b1); TestVirtual(d1); return 0; }
- 动态多态的条件:
- 基类中必须包含虚函数,并且派生类中一定要对基类中的虚函数进行重写
- 通过基类对象的指针或者引用调用虚函数
- 函数重写:
- 基类中将被重写的函数必须为虚函数
- 基类和派生类中虚函数的原型必须保持一致(返回值类型,函数名称以及参数列表),协变[基类(或者派生类)的虚函数返回基类(派生类)的指针(引用)]和析构函数(基类和派生类的析构函数是不一样的)除外
- 访问限定符可以不同
- 哪些函数不能定义为虚函数?
- 友元函数,它不是类的成员函数
- 全局函数
- 静态成员函数,它没有this指针
- 构造函数,拷贝构造函数,以及赋值运算符重载(可以但是一般不建议作为虚函数)
4.抽象类
- 在成员函数(必须为虚函数)的形参列表后面写上=0,则成员函数为纯虚函数。包含纯虚函数的类叫做抽象类(也叫接口类),抽象类不能实例化出对象。纯虚函数在派生类中重新定义以后,派生类才能实例化出对象。纯虚函数是一定要被继承的,否则它存在没有任何意义。