什么是多态?你对多态的认识?
简单来说就是同一事物在不同的场景下表现出的多种形态。
栗子:网上的例子,见人说人或话,见鬼说鬼话。
一个人见到不同身份的人说话的态度不一样。

多态的实现条件:

在继承的体系下
基类中必须有虚函数,被virtual修饰的成员函数(注意一定是成员函数),友元函数不是虚函数
在派生类中必须要对基类中的虚函数进行重写
对于虚函数的调用:必须使用基类的指针或者引用调用多态。多态的发生就是在基类的指针或者引用指向子类的对象的时候。

体现多态性:在代码运行时,基类指针指向哪个类的对象,就调用哪个类的虚函数

多态的实现:
汉语命名好玩,但是感觉好乱

class 人类
{public:人类(string 名字,string 性别,int 年龄):_名字(名字), _性别(性别), _年龄(年龄){}virtual void 买票(){cout << "全价票" << endl;}
protected:string _名字;  //姓名string _性别;   //性别int _年龄;  //年龄
};class 学生类 : public 人类
{public:学生类(string 名字, string 性别, int 年龄, int 学号):人类(名字, 性别, 年龄),_学号(学号){}virtual void 买票(){cout << "半价票" << endl;}
protected:int _学号;  //学号
};
class 军人类 : public 人类
{public:军人类(string 名字, string 性别, int 年龄, string 军衔):人类(名字, 性别, 年龄), _军衔(军衔){}virtual void 买票(){cout << "免票" << endl;}
protected:string _军衔;  //学号
};
int main()
{//必须通过基类的指针或引用来调用
//多态的体现就是:代码编译的时候不能确定到底调用哪个类的虚函数,要在代码运行时才可以确定下来军人类 张超伦("张超伦", "男", 28,"大佐");学生类 小董("小董", "男", 20, 1740);人类& 九一刘先生 = 张超伦;  //发生多态//根据基类指向的派生类的对象,才能确定调用哪一个类的虚函数人类& 小王 = 小董;   //发生多态九一刘先生.买票();小王.买票();return 0;
}

发生多态后打印结果:

重写:派生类重写基类的某个虚函数,派生类虚函数必须要和基类中虚函数的原型完全一致,原型完全一致指的是,返回值类型,函数名,参数类型,完全一致。
重写:一定是派生类重写基类的虚函数
1.一个函数在基类中,一个函数在子类中
2.基类中的成员函数必须是虚函数:基类的成员函数前必须增加virtual的关键字,
3.子类同名成员函数前virtual关键字是否田间都可以。子类加不加都可以,在子类中就算不加virtual关键字,但是实际上它还是虚函数,所以说建议最好加上。
4.基类虚函数必须要与派生类虚函数的原型完全一致(返回值类型,函数名,参数列表)。

关于原型完全一致也是存在**两个例外(协变,析构函数)**的:
协变:
基类中虚函数返回的是基类的引用或者指针,子类的虚函数返回子类的引用或者指针
此时就算在基类和派生类中虚函数原型不一致,这照样可以形成重写,也可以发生多态。

利用协变发生多态:

class Base
{public:virtual Base* test()    在基类中返回基类的指针或者引用{cout << "base()" << endl;return this;}
};
class Dri : public Base
{public:virtual Dri* test()   //在子类中返回子类的指针或者引用{cout << "Dri()" << endl;return this;}
};
void test(Base* p)
{p->test();
}
int main()
{Base b;Dri d;test(&b);test(&d);return 0;
}

关于协变的用法:

举例说名:

class A
{public:virtual A* test(){cout << "A" << endl;return this;}
};
class B : public A
{public:virtual A* test()  //返回值是基类的指针{cout << "B" << endl;return this;}
};
class C : public B
{public:virtual B* test()   //返回的是基类的指针{cout << "C" << endl;return this;}};
void test(A* p)
{p->test();
}
int main()
{A a;B b;C c;test(&a);test(&b);test(&c);return 0;
}

上面代码的关系:

2.析构函数:

class A
{public:A(){cout << "A" << endl;}virtual ~A()  //注意这里将析构函数给成了虚函数{cout << "~A()" << endl;}
};
class B : public A
{public:B() :p(new int[10]){cout << "B" << endl;}~B(){delete[] p;cout << "~B()" << endl;}int* p;
};
void test()
{A* p = new B;delete p;
}
int main()
{test();return 0;
}

打印结果:

假如不把A类的析构函数给成虚函数的话。

打印结果就变成了:

说明并没有调用子类的析构 ,也就是没有释放子类申请的空间

所以析构函数也是一个例外,虽然基类和派生类析构函数名不一样,但是照样发生了重写。

析构函数和构造函数都没有办法被继承,
构造函数可以被重载,析构函数不可以被重载
析构函数能作为虚函数,构造函数不可以作为虚函数

添加:
析构函数不可以声明为const
C++11auto是在编译时器进行推演,所以不可以推演函数参数和数组类型,
this指针可以为空,也就是说,自定义类型的指针指向空之后,照样存在有this指针。

析构函数不能被重载,构造函数可以被重载
析构函数和构造函数都不可以被继承
析构函数可以是虚函数,构造函数不可以是虚函数

static成员可以被继承
static成员不能被作为虚函数
static成员大小不包含在类的成员大小中
友元函数不可以被继承

一个类不想被继承可以使用final,
一个类不想实例化出对象,可以在类中的虚函数后面 添加=0,则此函数为纯虚函数,包含纯虚函数的类叫做抽象类,抽象类不能实例化出对象
派生类不充写抽象类中的纯虚函数的话也无法实例化对象
基类对象使用同一张虚表,虚表地址相同
派生类和基类永远不会使用同一张虚表,哪怕派生类并没有重写积累的虚函数,只是照搬下来,此时基类的派生类虚表地址不同(说明不是同一张虚表),但是内容一致

构造函数和析构函数可以抛出异常么?
首先是析构函数。

一. 析构函数

 参照《Effective C++》中条款08:别让异常逃离析构函数。

总结如下:

 1. 不要在析构函数中抛出异常!虽然C++并不禁止析构函数抛出异常,但这样会导致程序过早结束或出现不明确的行为。2. 如果某个操作可能会抛出异常,class应提供一个普通函数(而非析构函数),来执行该操作。目的是给客户一个处理错误的机会。3. 如果析构函数中异常非抛不可,那就用try catch来将异常吞下,但这样方法并不好,我们提倡有错早些报出来。

二. 构造函数

 总结如下:1. 构造函数中抛出异常,会导致析构函数不能被调用,但对象本身已申请到的内存资源会被系统释放(已申请到资源的内部成员变量会被系统依次逆序调用其析构函数)。2. 因为析构函数不能被调用,所以可能会造成内存泄露或系统资源未被释放。3. 构造函数中可以抛出异常,但必须保证在构造函数抛出异常之前,把系统资源释放掉,防止内存泄露。(如何保证???使用auto_ptr???)

最后总结如下:

  1. 构造函数中尽量不要抛出异常,能避免的就避免,如果必须,要考虑不要内存泄露!

  2. 不要在析构函数中抛出异常!

C++小工修炼之路XXI(多态上)相关推荐

  1. 传承or创新 ?解密分布式数据库自研修炼之路

    一直以来,数据库的核心研发团队都十分神秘,作为隐藏在幕后的隐士高人,他们对数据库研发的心得是什么?他们又对数据库的未来发展有什么看法呢?本文就由巨杉数据库核心技术研发团队的"老司机" ...

  2. 腾讯业务监控的修炼之路

    作者丨李光:现任职于腾讯社交网络运营部/织云产品团队,负责织云监控告警平台规划与运维新产品开发工作,具有多年业务运维.运营规划经验. 概述 本文作为监控告警产品的专题系列的第二篇文章,主要讨论的是IA ...

  3. +++程序员高手修炼之路

    正在做Andy Hunt和David Thomas的<程序员修炼之路>英文注释版(The Pragmatic Programmer)的最后审稿工作. 这本书虽然很早就读过一些,但现在再读, ...

  4. 我的前端成长之路:中医药大学毕业的业务女前端修炼之路

    简介: 前端工程师的修炼没有捷径,踏踏实实的通过一个个项目的实践来升级打怪实现进阶:本文仅分享自己11年的前端生涯,探讨一直在业务中的技术人的成长之路,也复盘再认识下自己,每个节点我遇到的问题和我的选 ...

  5. 码斗士的修炼之路 -- 如何保持并提升战斗力

    转自:http://www.cnblogs.com/multiplesoftware/archive/2011/05/19/2050670.html 那日,我与一友人漫步.他资质过人,少言寡欲, 刚二 ...

  6. 王者荣耀的技术修炼之路

    5 月 11 - 13 日,Unite 2017 Shanghai 在上海国际会议中心举行,在案例分享专场上,腾讯王者荣耀项目技术总监邓君为我们带来了<王者技术修炼之路>的主题演讲. 以下 ...

  7. 程序员修炼之路(十四)IT外企那点儿事--也说跳槽

    最近一个月一直在忙项目,几乎没什么时间写博客,今天中午才有时间看看csdn,在论坛上看到一篇很好的文章,分享给大家.也给自己留作备用. 原文地址:http://www.cnblogs.com/forf ...

  8. 一起学设计模式 - 一起开始设计模式的修炼之路

    文章目录 一起学设计模式 - 一起开始设计模式的修炼之路 1.为什么要学设计模式 2.设计模式的六大原则 2.1 单一职责原则(Single responsibility principle) 2.2 ...

  9. 实验室里的AI激情:腾讯优图的升级修炼之路

    一百多年来,信息技术从初兴到成为基础设施,成就了无数辉煌的科技巨头.如今,人工智能也正狂奔在通往社会通用性技术的路上. 要从上一波信息技术浪潮的产业规律中预测出AI的航海图,并不容易.但回到历史现场, ...

最新文章

  1. (附视频) | AI奠基人、美国AI科学家特伦斯谈深度学习​
  2. 一个教务系统多少钱_销售管理系统报价多少钱
  3. 计算机视觉与深度学习 | 深度学习与VO、SLAM、三维重建【论文及代码篇】
  4. Python的国际化
  5. 生成唯一id号解决方法
  6. linux-shell命令之rmdir(remove dir)【删除目录】
  7. 电脑重装系统后没声音怎么办
  8. Flutter进阶—实现动画效果(一)
  9. mysql 乱码处理
  10. [转载] 2012年上半年信管网论文复习建议
  11. php 密码加密方法
  12. 计算机二级vb上机操作题库,2017年3月计算机二级VB上机操作题库及答案
  13. 《机器学习实战》 自制勘误表 中文版第一版2015年9月第11次印刷版
  14. 打印机模拟(灰度篇)
  15. python基础 日常总结——列表(二)
  16. 如何实现视频加密全平台播放
  17. 浏览淘宝网页背后所发生的事情
  18. 英文歌曲:What I Have Done(变形金刚第一部主题曲)
  19. 大学生学完python靠几个接单网站兼职,实现经济独立
  20. net-java-php-python-高校新生报到管理系统计算机毕业设计程序

热门文章

  1. JAVA GUI中的窗体清空和窗体关闭方法分析
  2. 双链表的初始化(带头结点)
  3. 干货分享:十年大厂资深程序员的开发经验总结
  4. ThinkPad史上最强发布会:全家族新品致敬时代先锋
  5. weblogic11g清理缓存tmp
  6. vue3+ts issue —— vue.ts 不是模块。
  7. unigui设置文件下载类型
  8. 项目一:医疗费用预估
  9. 22春天津大学《钢筋混凝土结构(1)》在线作业2
  10. Android开发:使用Viewpager模仿驾考宝典试卷答题界面