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字节)。每个虚函数调用,都需要执行地址查找。

参考:

1.关于C++中的虚拟继承的一些总结

C++的继承与接口的更多相关文章

  1. Javascript面向对象特性实现封装、继承、接口详细案例——进级高手篇

    Javascript面向对象特性实现(封装.继承.接口) Javascript作为弱类型语言,和Java.php等服务端脚本语言相比,拥有极强的灵活性.对于小型的web需求,在编写javascript ...

  2. C#类继承和接口继承时一些模棱两可的问题[转]

    原文地址:http://www.cnblogs.com/harleyhu/archive/2012/11/29/2794809.html 1.在father定义的方法若含有virtual关键字,chi ...

  3. Java继承和接口

    接口最关键的作用,也是使用接口最重要的一个原因:能上溯造型至多个基础类.使用接口的第二个原因与使用抽象基础类的原因是一样的:防止客户程序员制作这个类的一个对象,以及规定它仅仅是一个接口.这样便带来了一 ...

  4. 基础学习day07---面向对象三---继承,接口与 抽象类

    一.继承 1.1.继承概念 将对象的共性抽取出来.提取出一个单独的类. 继承使用复用以前的代码非常容易,能够大大的缩短开发周期,降低开发成本,同时增加程序的易维护性 继承使重一个类A能够直接使用另外一 ...

  5. java 类的继承和接口的继承

    父类 public class person { String name; int age; void eat(){ System.out.println("吃饭"); } voi ...

  6. Effective C++ 笔记:条款 34 实现继承和接口继承

    Differentiate between inheritance of interface and inheritance of implementation. 行为含义 声明一个pure virt ...

  7. 【C# 复习总结】类、继承和接口

    1 类 定义新的数据类型以及这些新的数据类型进行相互操作的方法 定义方式: class Cat { } class Cat:object { } C#中所有的类都是默认由object类派生来的,显示指 ...

  8. Javascript面向对象特性实现封装、继承、接口详细案例

    Javascript面向对象特性实现(封装.继承.接口) Javascript作为弱类型语言,和Java.php等服务端脚本语言相比,拥有极强的灵活性.对于小型的web需求,在编写javascript ...

  9. java基础知识总结--继承和接口

    什么是继承?什么是接口?他们之间的区别和联系是什么? 什么是继承? 继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能.多个类中存在相同属性和行 ...

  10. PHP接口继承及接口多继承原理与实现方法详解

    在PHP的接口中,接口可以继承接口.虽然PHP类只能继承一个父类(单继承),但是接口和类不同,接口可以实现多继承,可以继承一个或者多个接口.当然接口的继承也是使用extends关键字,要多个继承的话只 ...

随机推荐

  1. 在CentOS6.4中安装配置LAMP环境的详细步骤 - Leroy-LIZH

    本文详细介绍了CentOS6.4系统中安装LAMP服务并对其进行配置的过程,即安装Apache+PHP+Mysql,参照了网上大神的设置,其他Linux发行系统可以参考~ 在本文中部分命令操作需要ro ...

  2. 无法锁定管理目录(/var/lib/dpkg/),是否有其他进程正占用它

    dpkg应用程序被占用 错误提示: E: 无法获得锁 /var/lib/dpkg/lock – open (11: 资源暂时不可用) E: 无法锁定管理目录(/var/lib/dpkg/),是否有其他 ...

  3. WPF TextBox 只能输入数字键

     <Grid>         <TextBox Name="textBox1" PreviewTextInput="textBox1_PreviewT ...

  4. ES6-Set和Map数据结构学习笔记

    Set和Map数据结构 Set 基本用法 ES6提供了新的数据结构--Set,类似于数组,但是成员的值是唯一的,没有重复的值,Set本身是一种构造函数,用来生成Set数据结构 var s = new ...

  5. python--基本代码规范

    python代码规范:一.标识符 所谓的标识符就是对变量.常量.函数.类等对象起的名字 python语言在任何场景都严格区分大小写!!! python对于标识符的命名有如下规定: 第一个字符必须是字母 ...

  6. php操作rabbitmq

    1.配置交换机,队列,然后绑定 <?php $conn_args = [ 'host' => '127.0.0.1', //rabbitmq 服务器host 'port' => 56 ...

  7. Leetcode 969. Pancake Sorting

    每次找到当前最大数,转两下把最大数转到最右边.重复这个操作,直到都转完. 时间复杂度O(n**2) class Solution(object): def pancakeSort(self, A): ...

  8. main函数的参数的用法

    说明:main函数的参数的用法源代码: #include <stdio.h>#include <stdlib.h>int main(int argc, char *argv[] ...

  9. 【整理】C++中的unique函数

    之前总结了一下我觉得有用的erase,lower_bound,upper_bound. 现在总结一下unique,unique的作用是“去掉”容器中相邻元素的重复元素(不一定要求数组有序),它会把重复 ...

  10. webpack 单页面应用实战

    这篇文章将介绍如何利用 webpack 进行单页面应用的开发,算是我在实际开发中的一些心得和体会,在这里给大家做一个分享.webpack 的介绍这里就不多说了,可以直接去官网查看. 关于这个单页面应用 ...