【c++】面向对象程序设计之关于继承
面向对象程序设计的核心思想是数据抽象(类的接口与实现分离)、继承和动态绑定
基类
虚函数:基类希望派生类各自定义适合自身的版本的函数
在c++中,当我们使用基类的引用或指针调用虚函数时将发生动态绑定。
基类通常都应该定义一个虚析构函数。C++规定:用不带有虚析构函数的基类的指针来删除一个派生类对象(基类指针指向派生类对象,delete该指针),这个对象的派生类部分没有被析构,造成内存泄漏。
注意:
1.应该为多态基类声明虚拟析构函数。如果一个类有一个虚函数,那么它也应该有一个虚析构函数
2.如果一个类不是被设计为基类或者它们并不是按照多态的方式来使用的(不是用基类指针或引用来指向派生类对象),不要为它们声明虚析构函数 ,vptr及virtual table的存在使得内存空间浪费
任何构造函数之外的非静态函数都可以是虚函数,virtual只能出现在类内部的声明语句之前而不能用于类外部的函数定义。如果基类把一个函数声明成虚函数,则该函数在派生类中隐式地也是虚函数。
构造函数不能是虚函数的原因:
1.从存储空间角度
如果构造函数是虚函数,就需要通过 vptr来调用,vptr是存储在对象的内存空间中,可是对象还没有实例化,也就是内存空间还没有,怎么找vptr呢?所以构造函数不能是虚函数。
2.从使用角度来看
虚函数作用是通过父类的指针或引用来调用它的时候能够变成调用子类的那个成员函数。而构造函数是在创建对象时自动调用的,不可能通过父类的指针或者引用去调用,因此也就规定构造函数不能是虚函数
static函数不能是虚函数的原因:
调用虚函数需要类的实例,static函数作为类函数,不属于类的实例,自然无法实现多态了。
派生类
派生类能访问public protected成员,不能访问private成员。
如果派生类没有覆盖其基类中的某个虚函数,则该虚函数的行为类似其他的普通成员,派生类会直接继承其在基类中的版本。c++11允许派生类显式地注明它使用某个成员函数覆盖了它继承的虚函数,在声明语句的最后添加override.
派生类必须使用基类的构造函数来初始化它的基类部分,通过构造函数初始化列表将实参传递给基类构造函数(否则使用默认构造函数)。首先初始化基类的部分,然后按照声明的顺序依次初始化派生类的成员。
派生类的声明包含类名但是不包含它的派生列表,派生列表必须与类的主体一起出现。
如果我们想将某个类用作基类,则该类必须已经定义而非仅仅声明。派生类中包含并且可以使用它从基类继承而来的成员,为了使用这些成员,派生类需要知道它们是什么,因此一个类不能派生它本身。vs中会报错:不允许使用不完整的类型
防止继承的发生:
c++11提供了一种防止继承发生的方法,即定义时在类名后跟关键字final。
当我们用一个派生类对象为一个基类对象初始化或赋值时,只有该派生类对象中的基类部分会被拷贝、移动或赋值,它的派生类部分将被忽略。
----------------------------------------------------------------------------------------------------------------
class ClxBase
{
public:
ClxBase() {};
virtual ~ClxBase() {}; virtual void DoSomething() { cout << "Do something in class ClxBase!" << endl; };
}; class ClxDerived : public ClxBase
{
public:
ClxDerived() {};
~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" << endl; }; void DoSomething() { cout << "Do something in class ClxDerived!" << endl; };
}; int main()
{
ClxBase *pTest = new ClxDerived;
pTest->DoSomething();
delete pTest; system("pause");
}
输出结果是:
Do something in class ClxDerived!
Output from the destructor of class ClxDerived!
如果把类ClxBase析构函数前的virtual去掉,那输出结果如下:
Do something in class ClxDerived!
上述例子中会先调用基类的构造函数,再调用派生类的构造函数;而析构时,先调用派生类的析构函数,再调用基类的析构函数
一般情况下类的析构函数里面都是释放内存资源,而析构函数不被调用的话就会造成内存泄漏。
基类的析构函数一般都是虚函数是为了当删除一个指向派生类对象的基类指针时,派生类的析构函数会被调用。由函数的调用流程可以得知,先确定指针的静态类型,然后在静态类型对应的类中查找该函数,当找到后,如果该函数是虚函数,那么会在运行时根据指针的动态类型来调用函数,否则编译时直接生成调用当前类中的该函数的代码。所以若析构函数不是虚函数,当删除一个指向派生类对象的基类指针时不会调用派生类的析构函数。
【c++】面向对象程序设计之关于继承的更多相关文章
- java面向对象三大特性之继承
通过重用已经测试并验证通过的代码,怎样才减少开发工作,所有开发团队都在为一问题而努力.一个久经考验的方法是通过有效地使用Java继承优化应用程序开发. 继承的从某种意义上讲,继承的短暂美就如同宇宙中所 ...
- 周强 201771010141 《面向对象程序设计(java)》第七周学习总结
实验目的与要求 (1)进一步理解4个成员访问权限修饰符的用途: (2)掌握Object类的常用API用法: (3)掌握ArrayList类用法与常用API: (4)掌握枚举类使用方法: (5)结合本章 ...
- JavaScript 面向对象程序设计(下)——继承与多态 【转】
JavaScript 面向对象程序设计(下)--继承与多态 前面我们讨论了如何在 JavaScript 语言中实现对私有实例成员.公有实例成员.私有静态成员.公有静态成员和静态类的封装.这次我们来讨论 ...
- javascript之面向对象程序设计(对象和继承)
总结的文章略长,慎点. 知识点预热 引用类型:引用类型的值(对象)是引用类型的一个实例.在ECMAScript中,引用类型是一种数据结构,用于将数据和功能组织在一起.在其他面向对象语言中被称为类,虽然 ...
- Java面向对象程序设计--与C++对比说明:系列3(Java 继承机制)
继承(inheritance)背后的核心思想是: bonus = b; } } Java没有像C++那样提供多继承机制,但提供了接口机制,在后面我们将详细探究接口机制的实现 ...
- Python基础(16)_面向对象程序设计(类、继承、派生、组合、接口)
一.面向过程程序设计与面向对象程序设计 面向过程的程序设计:核心是过程,过程就解决问题的步骤,基于该思想设计程序就像是在设计一条流水线,是一种机械式的思维方式 优点:复杂的问题的简单化,流程化 缺点: ...
- [.net 面向对象程序设计深入](2)UML——在Visual Studio 2013/2015中设计UML用例图
[.net 面向对象程序设计深入](2)UML——在Visual Studio 2013/2015中设计UML用例图 1.用例图简介 定义:用例图主要用来描述“用户.需求.系统功能单元”之间的关系. ...
- [.net 面向对象程序设计深入](1)UML——在Visual Studio 2013/2015中设计UML类图
[.net 面向对象程序设计深入](1)UML——在Visual Studio 2013/2015中设计UML类图 1.UML简介 Unified Modeling Language (UML)又称统 ...
- [.net 面向对象程序设计进阶] (13) 序列化(Serialization)(五) Json 序列化利器 Newtonsoft.Json 及 通用Json类
[.net 面向对象程序设计进阶] (13) 序列化(Serialization)(五) Json 序列化利器 Newtonsoft.Json 及 通用Json类 本节导读: 关于JSON序列化,不能 ...
随机推荐
- mysql5.6.35源码安装记录
mysql数据库源码安装: 源码地址:wget http://mirrors.163.com/mysql/Downloads/MySQL-5.6/mysql-5.6.xx.tar.gz #安装前准备, ...
- 【Java_基础】java中的常量池
1.java常量池的介绍 java中的常量池,通常指的是运行时常量池,它是方法区的一部分,一个jvm实例只有一个运行常量池,各线程间共享该运行常量池. java常量池简介:java常量池中保存了一份在 ...
- centos 7 中文乱码的解决办法
@@首先查看系统的操作版本,我的版本是centos 7.2 的. @@查看系统是否有安装中文语言包,一般我们在安装的时候系统都会默认的为我们安装上去的. locale -a | grep " ...
- Python面向对象(约束,异常处理,md5加密)(五)
1. 类的约束 1. 写一个父类. 父类中的某个方法要抛出一个异常 NotImplementedError class Base: def login(self): raise NotImplemen ...
- JavaScript正则表达式-相关的String对象方法
match()方法 match(regExp); 使用指定的正则表达式来搜索字符串. 如果找到匹配字符串返回一个数组,否则返回null. 返回的数组包含两个属性:index和input. index是 ...
- 算法学习记录-图——最小路径之Floyd算法
floyd算法: 解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径问题,同时也被用于计算有向图的传递闭包. 设为从到的只以集合中的节点为中间节点的最短路径的长度. 若最短路径经过 ...
- hadoop学习爬坑记录
1. Q: hdfs管理界面50070端口设置后,无法访问情况. A: 1)停止当前所有服务./stop-all.sh 2)在hdfs-site.xml中,更改开放端口的绑定IP: <prope ...
- 2017ACM/ICPC广西邀请赛-重现赛(感谢广西大学)
上一场CF打到心态爆炸,这几天也没啥想干的 A Math Problem Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/3 ...
- 用KMP征服循环节问题
以前我还是写过KMP的文章的 现在我们可以求一下循环节啊 Slot Machines Gym - 101667I #include<bits/stdc++.h> using namespa ...
- Luogu【P1901】发射站(单调栈)
题目链接 题目说明比自己矮的塔收不到自己的能量,摆明了就是单调栈呗. 把比自己矮的全都从栈里弹出去,于是碰到第一个比自己高的.让他接受自己发射的能量. 当然由于发射站发射的能量有两个方向,所以正反两遍 ...