C++小工修炼之路XXI(多态上)
什么是多态?你对多态的认识?
简单来说就是同一事物在不同的场景下表现出的多种形态。
栗子:网上的例子,见人说人或话,见鬼说鬼话。
一个人见到不同身份的人说话的态度不一样。
多态的实现条件:
在继承的体系下
基类中必须有虚函数,被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???)
最后总结如下:
构造函数中尽量不要抛出异常,能避免的就避免,如果必须,要考虑不要内存泄露!
不要在析构函数中抛出异常!
C++小工修炼之路XXI(多态上)相关推荐
- 传承or创新 ?解密分布式数据库自研修炼之路
一直以来,数据库的核心研发团队都十分神秘,作为隐藏在幕后的隐士高人,他们对数据库研发的心得是什么?他们又对数据库的未来发展有什么看法呢?本文就由巨杉数据库核心技术研发团队的"老司机" ...
- 腾讯业务监控的修炼之路
作者丨李光:现任职于腾讯社交网络运营部/织云产品团队,负责织云监控告警平台规划与运维新产品开发工作,具有多年业务运维.运营规划经验. 概述 本文作为监控告警产品的专题系列的第二篇文章,主要讨论的是IA ...
- +++程序员高手修炼之路
正在做Andy Hunt和David Thomas的<程序员修炼之路>英文注释版(The Pragmatic Programmer)的最后审稿工作. 这本书虽然很早就读过一些,但现在再读, ...
- 我的前端成长之路:中医药大学毕业的业务女前端修炼之路
简介: 前端工程师的修炼没有捷径,踏踏实实的通过一个个项目的实践来升级打怪实现进阶:本文仅分享自己11年的前端生涯,探讨一直在业务中的技术人的成长之路,也复盘再认识下自己,每个节点我遇到的问题和我的选 ...
- 码斗士的修炼之路 -- 如何保持并提升战斗力
转自:http://www.cnblogs.com/multiplesoftware/archive/2011/05/19/2050670.html 那日,我与一友人漫步.他资质过人,少言寡欲, 刚二 ...
- 王者荣耀的技术修炼之路
5 月 11 - 13 日,Unite 2017 Shanghai 在上海国际会议中心举行,在案例分享专场上,腾讯王者荣耀项目技术总监邓君为我们带来了<王者技术修炼之路>的主题演讲. 以下 ...
- 程序员修炼之路(十四)IT外企那点儿事--也说跳槽
最近一个月一直在忙项目,几乎没什么时间写博客,今天中午才有时间看看csdn,在论坛上看到一篇很好的文章,分享给大家.也给自己留作备用. 原文地址:http://www.cnblogs.com/forf ...
- 一起学设计模式 - 一起开始设计模式的修炼之路
文章目录 一起学设计模式 - 一起开始设计模式的修炼之路 1.为什么要学设计模式 2.设计模式的六大原则 2.1 单一职责原则(Single responsibility principle) 2.2 ...
- 实验室里的AI激情:腾讯优图的升级修炼之路
一百多年来,信息技术从初兴到成为基础设施,成就了无数辉煌的科技巨头.如今,人工智能也正狂奔在通往社会通用性技术的路上. 要从上一波信息技术浪潮的产业规律中预测出AI的航海图,并不容易.但回到历史现场, ...
最新文章
- (附视频) | AI奠基人、美国AI科学家特伦斯谈深度学习​
- 一个教务系统多少钱_销售管理系统报价多少钱
- 计算机视觉与深度学习 | 深度学习与VO、SLAM、三维重建【论文及代码篇】
- Python的国际化
- 生成唯一id号解决方法
- linux-shell命令之rmdir(remove dir)【删除目录】
- 电脑重装系统后没声音怎么办
- Flutter进阶—实现动画效果(一)
- mysql 乱码处理
- [转载] 2012年上半年信管网论文复习建议
- php 密码加密方法
- 计算机二级vb上机操作题库,2017年3月计算机二级VB上机操作题库及答案
- 《机器学习实战》 自制勘误表 中文版第一版2015年9月第11次印刷版
- 打印机模拟(灰度篇)
- python基础 日常总结——列表(二)
- 如何实现视频加密全平台播放
- 浏览淘宝网页背后所发生的事情
- 英文歌曲:What I Have Done(变形金刚第一部主题曲)
- 大学生学完python靠几个接单网站兼职,实现经济独立
- net-java-php-python-高校新生报到管理系统计算机毕业设计程序