11_c++多态
来源:互联网 发布:大数据平台技术架构 编辑:程序博客网 时间:2024/06/07 21:25
c++多态
参考文章:https://www.cnblogs.com/dormant/p/5223215.html
1、什么是多态
在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数。即对象类型是派生类,就调用派生类的函数;对象类型是基类,就调用基类的函数。
class Human{private: int a;public: virtual void eating(void){ cout<<"use hand to eat"<<endl; }/* 基类实现虚函数 */};class Englishman : public Human {public: void eating(void) { cout<<"use knife to eat"<<endl; }//派生类重写该函数};class Chinese : public Human {public: void eating(void) { cout<<"use chopsticks to eat"<<endl; }//派生类重写该函数};void test_eating(Human& h)//多态只发生在引用和指针中,值传递则不行。{ h.eating();//根据对象的实际类型调用不同的eating函数}int main(int argc, char **argv){ Human h; Englishman e; Chinese c; test_eating(h); test_eating(e); test_eating(c); return 0;}
2、为什么需要多态?
网上的例子:将父类比喻为电脑的外设接口,子类比喻为外设,现在我有移动硬盘、U盘以及MP3,它们3个都是可以作为存储但是也各不相同。如果我在写驱动的时候,我用父类表示外设接口,然后在子类中重写父类那个读取设备的虚函数,那这样电脑的外设接口只需要一个。但如果我不是这样做,而是用每个子类表示一个外设接口,那么我的电脑就必须有3个接口分别来读取移动硬盘、U盘以及MP3。若以后我还有SD卡读卡器,那我岂不是要将电脑拆了,焊个SD卡读卡器的接口上去?
一个接口,多种实现面向接口编程,大家都遵循这个接口。
3、多态的本质
存在虚函数的类都有一个一维的虚函数表叫做虚表,类的对象有一个指向虚表开始的虚指针。虚表是和类对应的,虚表指针是和对象对应的。 通过虚表指针就可以调用到类对象自身的函数。
class Human{
private:
int a;
public:
virtual void eating(void){ cout<<”use hand to eat”<
4、多态的注意事项
a、析构函数一般都声明为虚构函数。
如下例子,如果析构函数不声明为虚函数,那么对象在被销毁的时候将会出错。
class Human{private: int a;public: virtual void eating(void){ cout<<"use hand to eat"<<endl; } virtual ~Human() { cout<<"~Human()"<<endl; }};class Englishman : public Human{public: void eating(void){cout<<"use knife to eat"<<endl;} virtual ~Englishman(){cout<<"~Englishman()"<<endl;}};class Chinese : public Human {public: void eating(void) { cout<<"use chopsticks to eat"<<endl; } virtual ~Chinese() { cout<<"~Chinese()"<<endl; }};void test_eating(Human h){ h.eating();}int main(int argc, char **argv){ Human * h = new Human; Englishman *e = new Englishman; Chinese *c = new Chinese; Human *p[3] = {h, e, c}; int i; for(i = 0; i < 3; i++) { p[i]->eating();
/* 如果析构函数不声明为析构函数, * 这里销毁对象时,将会调用3次Human * 的析构函数,这显然是不对的。 */ delete p[i]; } return 0;}
b、如果虚函数在基类与派生类中出现,仅仅是名字相同,而形式参数不同,或者是返回类型不同,那么即使加上了virtual关键字,也是不会进行滞后联编的。 但是有一种情况返回值可以不同,就是返回类的指针。即返回不同类的指针的同名、同参数的函数可以实现多态。
class Human{private: int a;public: virtual void eating(void){cout<<"use hand to eat"<<endl;} virtual ~Human() { cout<<"~Human()"<<endl; } virtual Human* test(void) {cout<<"Human's test"<<endl; return this; }};class Englishman : public Human {public: void eating(void) { cout<<"use knife to eat"<<endl; } virtual ~Englishman() { cout<<"~Englishman()"<<endl; } virtual Englishman* test(void) {cout<<"Englishman's test"<<endl; return this; }};class Chinese : public Human {public: void eating(void) { cout<<"use chopsticks to eat"<<endl; } virtual ~Chinese() { cout<<"~Chinese()"<<endl; } virtual Chinese* test(void) {cout<<"Chinese's test"<<endl; return this; }};void test_eating(Human& h){ h.eating();}void test_return(Human& h){ h.test();//test函数的返回值为对象的指针,可以实现多态}int main(int argc, char **argv){ Human h; Englishman e; Chinese c; test_return(h); test_return(e); test_return(c); return 0;}
c、只有类的成员函数才能说明为虚函数,因为虚函数仅适合用与有继承关系的类对象,所以普通函数不能说明为虚函数。
d、静态成员函数不能是虚函数,因为静态成员函数的特点是不受限制于某个对象。
e、内联(inline)函数不能是虚函数,因为内联函数不能在运行中动态确定位置。即使虚函数在类的内部定义定义,但是在编译的时候系统仍然将它看做是非内联的。
f、构造函数不能是虚函数,因为构造的时候,对象还是一片位定型的空间,只有构造完成后,对象才是具体类的实例。
- 11_c++多态
- 排序算法_C++11的实现
- 排序算法_C++11的实现
- 11_C# 实现VMS客户端——控件_ComboBoxEx
- 20170911_C++11新特性之智能指针
- 趣味_C#
- 07.02_c
- 二分_C
- 20091009_C#_GeneratePWD
- 单件模式_C++
- POJ 2602_C
- 基础_C# 数组
- 基础_C# 字符串
- 基础_C# 事件
- 基础_C# 委托
- 基础_C# 接口
- 基础_C# 泛型
- 基础_C# 迭代器
- servlet单例多线程
- Ubuntu 安装curl
- JQuery 对 Select option 的操作(转)
- (ssl 1203 洛谷 1281)书的复制
- Halide学习笔记----Halide tutorial源码阅读8
- 11_c++多态
- 数据结构实验之排序四:寻找大富翁
- 支持向量机原理(理解SVM的三层境界)
- 顺序+每次迭代,顺序+每次出现
- 高新集训D3D4总结
- 橡皮怪Dici,over,welcome,player
- C# GDI+绘图
- git语法
- 修改Anaconda中的Jupyter Notebook默认工作路径