C++的继承与接口
1.继承方式
三种继承方式,public,private,protected。注意,继承方式是相对于某一层类的方法而言,并不是相对于子类的对象而言。对于外部世界()对象来说,protected和private相似。对于派生类来说,protected和public相似。
public继承。派生类中,父类public和protected的成员可以直接访问,仍旧保持public属性。派生类对象,父类public成员可以访问。
private继承。派生类中,父类public和protected的成员可以直接访问,但是已经成为了private属性。直接后果:其一是派生类对象不能直接访问这些成员了(类外私有);其二、派生类的子类也不能直接访问这些成员了(已经私有属性,只能经由该层派生类访问)。
protected继承。派生类中,父类public和protected的成员可以直接访问,但是已经成为了protected属性。直接后果:派生类对象不能不能直接访问这些成员了(私有),同样派生类的子类可以继访问(protected)。
总结而言:
基类中 继承方式 子类中
public & public继承 => public
public & protected继承 => protected
public & private继承 = > private
protected & public继承 => protected
protected & protected继承 => protected
protected & private继承 = > private
private & public继承 => 子类无权访问
private & protected继承 => 子类无权访问
private & private继承 = > 子类无权访问
2.虚继承
虚继承时为了解决多重继承出现的钻石继承导致子对象重复。虚继承可以节省内存。当然节省了内存牺牲了时间。相较于普通继承而言,虚继承:
(1)时间上在通过继承类对象访问虚基类对象中的成员(包括数据成员和函数成员)时,都必须通过某种间接引用来完成,这样会增加引用寻址时间(就和虚函数一样),其实就是调整this指针以指向虚基类对象,只不过这个调整是运行时间接完成的。
(2)空间上由于共享所以不必要在对象内存中保存多份虚基类子对象的拷贝,这样较之多继承节省空间(避免了同时出现两个基类子对像)。在虚拟继承情况下,基类子对象的布局是不同于普通继承的。因此,它需要多出一个指向基类子对象的指针。
考虑以下情况:
分别求sizeof(a),sizeof(b)。结果为:
第一种:4,12
第二种:4,4
第三种:8,16
第四种:8,8
分析:
考虑a: 涉及到内存对齐(由于每一个类均有虚函数,每个对象隐含保存虚指针指向类虚函数表,大小占4),故a的大小很好判断。
考虑b: 实际上:
第一个:vfptr(b:foo)+vbptr+vfptr(a:func)=12
第二个:vfptr(a:func, b:foo)=4
第三个:vfptr(b:foo)+vbptr+vfptr(a:func)+x(对齐为四个字节)=16
第四个:vfptr(a:func, b:foo)+x(对齐为四个字节)=8
含有虚函数的类均有指向自身虚函数表的虚指针。只是虚继承时,虚函数表仅有自身的虚函数地址,而非虚函数,且每一层的虚指针都存在,且派生类包括一个指向父类对象的虚指针。对于非虚继承,始终有且仅有一个虚指针,且包含所有虚函数地址。
同样:
class A{
char k[3];
public :
virtual void a(){};
};
class B1:public virtual A{
char k[3];
public :
virtual void b(){};
};
class C1:public virtual B1{
char k[3];
public :
virtual void c(){};
};
class B2:public A{
char k[3];
public :
virtual void b(){};
};
class C2:public B2{
char k[3];
public :
virtual void c(){};
};
A B1 C1 大小为8 20 32
A B2 B1 大小为8 12 16
3.重载、覆盖、隐藏的区别
重载:类内重载,同名不同参数。注意,虚函数也可以有包含重载类型,此时派生类必须对所有重载类型再次定义。
覆盖:派生覆盖,即派生类函数覆盖基类函数,同名同参且为虚函数。即虚函数机制属于覆盖类型。
隐藏:派生隐藏,即派生类的函数屏蔽了基类函数,同名不要求参数。虚函数也存在隐藏现象,即派生类存在同名不同参数的虚函数,会导致基类同名虚函数被隐藏。
4.虚指针与虚函数表
(1)虚(函数)指针用于虚函数的实现细节,带虚函数的类的每一个对象都有一个虚指针指向该类的虚函数列表。
(2)每个虚函数都在虚函数表占有一个地址。派生类对象包含指向独立地址表的指针。若提供了虚函数的新定义,则虚函数表保持性函数的地址,否则保留父类虚表的地址。
(3)不论类中有多少虚函数。类的对象只有一个虚函数指针指向该类的虚表。
(4)使用虚函数时。每个对象存储都增大,即包含指针存储空间(通常4字节)。每个虚函数调用,都需要执行地址查找。
参考:
C++的继承与接口的更多相关文章
- Javascript面向对象特性实现封装、继承、接口详细案例——进级高手篇
Javascript面向对象特性实现(封装.继承.接口) Javascript作为弱类型语言,和Java.php等服务端脚本语言相比,拥有极强的灵活性.对于小型的web需求,在编写javascript ...
- C#类继承和接口继承时一些模棱两可的问题[转]
原文地址:http://www.cnblogs.com/harleyhu/archive/2012/11/29/2794809.html 1.在father定义的方法若含有virtual关键字,chi ...
- Java继承和接口
接口最关键的作用,也是使用接口最重要的一个原因:能上溯造型至多个基础类.使用接口的第二个原因与使用抽象基础类的原因是一样的:防止客户程序员制作这个类的一个对象,以及规定它仅仅是一个接口.这样便带来了一 ...
- 基础学习day07---面向对象三---继承,接口与 抽象类
一.继承 1.1.继承概念 将对象的共性抽取出来.提取出一个单独的类. 继承使用复用以前的代码非常容易,能够大大的缩短开发周期,降低开发成本,同时增加程序的易维护性 继承使重一个类A能够直接使用另外一 ...
- java 类的继承和接口的继承
父类 public class person { String name; int age; void eat(){ System.out.println("吃饭"); } voi ...
- Effective C++ 笔记:条款 34 实现继承和接口继承
Differentiate between inheritance of interface and inheritance of implementation. 行为含义 声明一个pure virt ...
- 【C# 复习总结】类、继承和接口
1 类 定义新的数据类型以及这些新的数据类型进行相互操作的方法 定义方式: class Cat { } class Cat:object { } C#中所有的类都是默认由object类派生来的,显示指 ...
- Javascript面向对象特性实现封装、继承、接口详细案例
Javascript面向对象特性实现(封装.继承.接口) Javascript作为弱类型语言,和Java.php等服务端脚本语言相比,拥有极强的灵活性.对于小型的web需求,在编写javascript ...
- java基础知识总结--继承和接口
什么是继承?什么是接口?他们之间的区别和联系是什么? 什么是继承? 继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能.多个类中存在相同属性和行 ...
- PHP接口继承及接口多继承原理与实现方法详解
在PHP的接口中,接口可以继承接口.虽然PHP类只能继承一个父类(单继承),但是接口和类不同,接口可以实现多继承,可以继承一个或者多个接口.当然接口的继承也是使用extends关键字,要多个继承的话只 ...
随机推荐
- bootstrap参考网站
http://www.chuntao.org.cn/http://www.dianxiaohuo.com/
- java: i18n语言
<%@ page language="java" contentType="text/html; charset=utf8"%> <%@ pa ...
- 解决 Amoeba连接mysql出错 解决方案
今天配置mysql的主从复制 用到了Amoeba.从安装到启动服务,我深深地体会到学运维的不易. 首先是 安装错误 的解决,连接错误 的兄弟可以直接往下拉. 安装错误 1.出现 JAVA_HOM ...
- windows下安装virtualenvwrapper之后workon不是内部或外部指令
virtualenvwrapper是虚拟环境的操作,在windows下需要使用以下命令安装: pip install virtualenvwrapper-win 安装win下的环境 相关操作:work ...
- 在.Net下使用redis基于StackExchange.Redis--登录功能
研究了下redis在.net下的使用,因为以前在java上用redis用的是jedis操作,在.net不是很熟悉,在网站上也看了一部分的.net下redis的使用,大部分都是ServiceStack. ...
- Android EditText输入光标居于开头最开始位置
如果欲使EditText加载后的输入光标自动处于最开始处,可以通过设置EditText的android:gravity实现,设置android:gravity为left或者start即可,可以设置: ...
- java学习笔记 --- IO(1)
1.File类:文件和目录(文件夹)路径名的抽象表示形式,把文件或者目录(文件夹)都封装成File对象 1.构造方法 File(String pathname):根据一个路径得到File对象 File ...
- json与DataTable相互转换
首先我们看看 Newtonsoft.Json.JsonConvert 是怎么完成的: DataTable table = new DataTable(); table.Columns.Add(&quo ...
- 利用HTML5开发Android笔记(下篇)
资源来自于www.mhtml5.com 杨丰盛老师成都场的PPT分享 一个很简明的demo 可以作为入门基础 学习的过程中做了点笔记 整理如下 虽然内容比较简单 但是数量还是比较多的 所以分了3篇 ( ...
- thinkphp3.0中ajax的发送
系统支持任何的AJAX类库,Action类提供了ajaxReturn方法用于 AJAX调用后返回数据给客户端.并且支持JSON.XML和EVAL三种方式给客户端接受数据,通过配置DEFAULT_AJA ...