多态(1)—— 多态的定义、多态的三个必要条件、静态联编和动态联编、虚析构函数、重载重写重定义
1、多态的意义
如果有几个上似而不完全相同的对象,有时人们要求在向它们发出同一个消息时, 它们的反应各不相同,分别执行不同的操作。这种情况就是多态现象。
C++中所谓的多态(polymorphism)是指,由继承而产生的相关的不同的类,其对象对同一消息会作出不同的响应。
2、多态的三个必要条件
- 要有继承
- 要有虚函数重写
- 要有父类指针(父类引用)指向子类对象
#include <iostream> #include <string> using namespace std; class Yuebuqun { public: Yuebuqun(string kongfu) { this->kongfu = kongfu; } virtual void fight()//表示修饰一个成员方法是一个虚函数,必要条件2 { cout << "岳不群" << "使用了" << this->kongfu << endl; } string kongfu; }; //林平之继承了岳不群 class Linpingzhi :public Yuebuqun { public: Linpingzhi(string kongfu) :Yuebuqun(kongfu) { } //如果说父类中有一个虚函数是fight(),子类如果去重写这个虚函数, //那么如果传递进来的是子类,调用子类的fight,如果传递进来的是父类,调用父类的fight void fight()//必要条件2 { cout << "林平之" << "使用了" << kongfu << endl; } }; //令狐冲继承了岳不群 class Linghuchong :public Yuebuqun { public: Linghuchong(string kongfu) :Yuebuqun(kongfu) { } void fight() { cout << "令狐冲" << "使用了" << kongfu << endl; } }; //在全局提供一个打斗的方法 void fightPeople(Yuebuqun *hero)//必要条件3,相当于Yuebuqun *hero = xiaopp;或Yuebuqun *hero = xiaoyy; //或Yuebuqun *hero = xiaoll; { hero->fight();//希望如果传递进来的是子类,调用子类的fight; //如果传递进来的是父类,调用父类的fight //这种行为就是多态行为 } //多态发生的三个必要条件: //1.要有继承 //2.要有虚函数重写 //3.父类指针或引用指向子类对象 int main(void) { Yuebuqun *xiaoyy = new Yuebuqun("葵花宝典"); xiaoyy->fight(); Linpingzhi *xiaopp = new Linpingzhi("辟邪剑谱"); xiaopp->fight(); Linghuchong *xiaoll = new Linghuchong("独孤九剑"); xiaoll->fight(); //多态的实现 fightPeople(xiaoyy);//岳不群使用了葵花宝典 fightPeople(xiaopp);//林平之使用了辟邪剑谱 fightPeople(xiaoll);//令狐冲使用了独孤九剑 //编译器默认做了一个安全的处理,编译认为不管传递时子类对象还是父类对象, //如果统一执行父类的方法,那么一定可以被成功执行。 delete xiaoyy; delete xiaopp; delete xiaoll; return 0; }
3、静态联编和动态联编
(1)联编是指一个程序模块、代码之间互相关联的过程。
(2)静态联编,是程序的匹配、连接在编译阶段实现,也称为早期匹配。重载函数使用静态联编。
(3)动态联编是指程序联编推迟到运行时进行,所以又称为晚期联编(迟邦定)。switch语句和if语句是动态联编的例子。
1、C++与C相同,是静态编译型语言;
2、在编译时,编译器自动根据指针的类型判断指向的是一个什么样的对象;所以编译器认为父类指针指向的是父类对象;
3、由于程序没有运行,所以不可能知道父类指针指向的具体是父类对象还是子类对象,从程序安全的角度,编译器假设父类指针只指向父类对象,因此编译的结果为调用父类的成员函数。这种特性就是静态联编;
4、多态的发生是动态联编,实在程序执行的时候判断具体父类指针应该调用的方法。
4、虚析构函数
- 构造函数不能是虚函数。建立一个派生类对象时,必须从类层次的根开始,沿着继承路径逐个调用基类的构造函数。
- 析构函数可以是虚的。虚析构函数用于指引delete运算符正确析构动态对象。
5、重载重写重定义
重载(添加)
a、相同的范围(在同一个类中)
b、函数名字相同
c、参数不同
d、virtual可有可无
重写(覆盖) 是指派生类函数覆盖基类函数,特征是:
a、不同的范围,分别位于基类和派生类中
b、函数名字相同
c、参数相同
d、基类函数必须有virtual关键字
重定义(隐藏) 是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
a、如果派生类的函数和基类的函数同名,但是参数不同,此时,不管有无virtual,基类的函数被隐藏。
b、如果派生类的函数与基类的函数同名,但是参数也相同,但是基类函数没有virtual关键字,此时,基类的函数被隐藏。