- 所谓多态,就是不同类的对象的同一方法表现出不同的形态。比如定义一个铃响的方法,一些对象去食堂用餐,另一个对象下班回家
- 实现多态的三个必要条件
类之间存在继承关系
不同类的同一方法以虚函数的方法实现(virtual重写)
基类指针指向子类对象
- virtual多态关键字的意义,告诉编译器该函数要实现多态,不是根据指针类型判断如何调用,而是根据指针指向的对象类型来调用
- 从现象看定义一个基类mycoach和子类studentcoach,他们都实现了一个·gethint()方法,这里我们假定搏击名将居马别克(基类实现)是搏击小将陈培昌(继承基类的子类)的老师
- mycoach类实现
#pragma once #include<iostream> #include<string> using namespace std; class mycoach { private: string name; string addr; int age; string item; string place="热瓦甫新疆大餐厅"; public: mycoach::mycoach(string name,int age,string addr) { this->name = name; this->age = age; this->addr = addr; cout << ".........." << endl; } virtual void gethint(string item = "登山",string hint="内地朋友请注意呼吸,如果不舒服,就歇一会儿") { cout << "亲爱的朋友们!我是:" << this->name << ",欢迎参加----" << this->addr << endl; cout << "让我们来训练" << item << endl; cout << hint << endl; cout << "阿依古丽,带领姑娘们准备好担架,和骆驼队" << endl; } ~mycoach() { cout << "mycoach析构开始调用........." << endl; cout << "今天的训练先告一段落,下一个目标:" << this->place << ",let's go " <<endl; } };
- studentcoach类实现
#pragma once #include "mycoach.h" using namespace std; class studentcoach:public mycoach { private: string name; int age; string item; string addr; string place = "省港茶餐厅"; public: studentcoach::studentcoach(string name,int age,string addr):mycoach(name, age, addr),name(name) { //this->name = name; this->age = age; this->addr = addr; } void gethint(string item = "登山", string hint = "北方的朋友要siao(小)心山蚂蟥") { cout << "大嘎(家)好!唔系:" << this->name << ",欢迎参加----" << this->addr << endl; cout << "让我们来训练" << item << endl; cout << hint << endl; cout << "阿珍,叫王刘发娟,林许家娇,大嘎(家)准备好医疗用品" << endl; } ~studentcoach() { cout << "studentcoach析构开始调用........." << endl; cout << "今天的训练先告一段落,阿发,骑猛犸大三轮,带大家去---" << this->place << ",丁大锅跟我一辆车 " << endl; } };
- 主函数中定义的方法
#include<iostream> #include"mycoach.h" #include"studentcoach.h" using namespace std; void startpractise(mycoach *coach,string item="登山",string hint="内地的朋友,请到呼斯满那集合,他将带领你们适应高原的训练") { coach->gethint(item,hint);//这里将实现多态,而不仅仅是父类的方法 } void showdemo()//这种刻意封装是为了函数执行完,回收内存空间时触发对象的析构函数,以便看到对象析构函数执行效果 { mycoach jmbk("居马别克", 34, "天山搏击训练营"); //jmbk.gethint("长跑","内地的朋友,请到呼斯满那集合,他将带领你们适应高原的训练"); startpractise(&jmbk); studentcoach cpc("陈培昌", 22, "粤港人搏击俱乐部"); startpractise(&cpc, "登山", "北方的朋友要siao(小)心山蚂蟥"); //cpc.gethint(); } int main() { showdemo(); system("pause"); return 0; }
输出结果:
..........
亲爱的朋友们!我是:居马别克,欢迎参加----天山搏击训练营
让我们来训练登山
内地的朋友,请到呼斯满那集合,他将带领你们适应高原的训练
阿依古丽,带领姑娘们准备好担架,和骆驼队
..........
大嘎(家)好!唔系:陈培昌,欢迎参加----粤港人搏击俱乐部
让我们来训练登山
北方的朋友要siao(小)心山蚂蟥
阿珍,叫王刘发娟,林许家娇,大嘎(家)准备好医疗用品
studentcoach析构开始调用.........
今天的训练先告一段落,阿发,骑猛犸大三轮,带大家去---省港茶餐厅,丁大锅跟我一辆车
mycoach析构开始调用.........
今天的训练先告一段落,下一个目标:热瓦甫新疆大餐厅,let's go
mycoach析构开始调用.........
今天的训练先告一段落,下一个目标:热瓦甫新疆大餐厅,let's go
请按任意键继续. . .
- 多态实现原理
如果类中声明了virtual函数,编译器会做两件事情,创建一个虚函数列表,存入指向虚函数的指针;为对象创建一个vptr指针
运行时,根据对象的vptr指针指向的虚函数表中查找到相关函数,并调用 查找和调用都在运行时进行----这就是所谓的动态联编
也不难看出,virtual函数的执行涉及了寻址操作,这与普通函数在编译时就确定调用相比,多了些操作,势必造成性能开销,所以没必要把每一个成员函数都声明为virtual类型