在学习设计模式时我就有一个疑问,关联和继承除了用法上的区别,好像在内存上并没有什么区别,继承也是父类作为了子类的元素(内存上),关联也是这样。而且关联好像更占内存一些。这就是设计模式里问题了“依赖倒转原则”。

继承分为public继承,protect继承,private继承

public:父类中的public,protected成员到了派生类中属性不变。

protected:父类中的public,protected成员到了派生类中,都变为protected成员。

private:父类中的public,protected成员到了派生类中,都变成了private成员。

特别注意:父类中的private成员是不会被继承到子类中的(这也是关联和继承的一个区别)。

特别注意:还有一种继承被称为虚继承

详细回顾一下虚继承:

虚继承的形式:

class 派生类:virtual public 基类1,virtual public 基类2, virtual public 基类3……

{
};

构造函数过程:

首先执行虚基类的构造函数,多个虚基类的构造函数按照被继承的顺序构造;

执行基类的构造函数,多个基类的构造函数按照被继承的顺序构造;

执行成员对象的构造函数,多个成员对象的构造函数按照申明的顺序构造;

执行派生类自己的构造函数;

析构以与构造相反的顺序执行;

虚继承的实质是,在多继承中,派生类的基类中如果有过个基类继承至同一基类,那么这几个基类肯定含有这同一基类的拷贝(各自各一份),所以在派生类中如果想使用,就必须加上作用域分辨符来唯一识别。这时如果另这些基类继承时用上虚基类就可以解决这个问题了。我们可以将共同继承的基类,设为虚基类,这时从不同路径继承过来的同名的数据成员在内存中就只有一份拷贝, 同名函数也只有一个映射。

 #include<iostream>

 using namespace std;

 class Base
{
private:
int val;
public:
Base(){ cout << "Base无参构造函数" << endl; };
Base(int val){ this->val = val; cout << "Base有参构造函数" << endl; }
void print(){ cout << "val = "<<val << endl; }
}; class Sub1 :virtual public Base
{
public :
Sub1(int val) :Base(val){ cout << "Sub1含参构造函数" << endl; };
}; class Sub2 :virtual public Base
{
public:
Sub2(int val) :Base(val){ cout << "Sub2含参构造函数" << endl; }
}; class Child :public Sub1, public Sub2
{
public :
Child(int val) :Sub1(val), Sub2(val){ cout << "Child含参构造函数" << endl; }
}; int main()
{
Child child();
child.print();
}

输出结果:

Base无参构造函数
Sub1含参构造函数
Sub2含参构造函数
Child含参构造函数
val = -858993460
Press any key to continue . . .

可见Sub1,和Sub2构造函数并没有执行Base的构造函数,虚继承的构造函数是这样的,先执行虚基类的无参构造函数,然后在执行Sub1的构造函数,在执行Sub2的构造函数,在执行Child的构造函数,并且在执行Sub1和Sub2的构造函数时并不再执行Base的构造函数。

如果不用虚继承的访问方式:

 #include<iostream>

 using namespace std;

 class Base
{
private:
int val;
public:
Base(){ cout << "Base无参构造函数" << endl; };
Base(int val){ this->val = val; cout << "Base有参构造函数" << endl; }
void print(){ cout << "val = "<<val << endl; }
}; class Sub1 :public Base
{
public :
Sub1(int val) :Base(val){ cout << "Sub1含参构造函数" << endl; };
}; class Sub2 :public Base
{
public:
Sub2(int val) :Base(val){ cout << "Sub2含参构造函数" << endl; }
}; class Child :public Sub1, public Sub2
{
public :
Child(int val) :Sub1(val), Sub2(val){ cout << "Child含参构造函数" << endl; }
}; int main()
{
Child child(); //child.print() //非法的访问 child.Sub1::print();
child.Sub2::print();
}

结果:

Base有参构造函数
Sub1含参构造函数
Base有参构造函数
Sub2含参构造函数
Child含参构造函数
val = 3
val = 3
Press any key to continue . . .

C++ 虚基类 派生与继承的更多相关文章

  1. C++ (P160—)多继承 二义性 虚基类 “向上转型”

    1 多继承中,必须给每个基类指定一种派生类型,如果缺省,相应的基类则取私有派生类型,而不是和前一个基类取相同的派生类型 2 一个类的保护成员只能被本类的成员函数或者它的派生类成员函数访问 3 由于c+ ...

  2. C++ 多继承与虚基类

    转载来自:CSDN insistGoGo  (http://blog.csdn.net/insistgogo) 多继承的定义:派生类的基类大于一个 语法: class  派生类名:继承方式1 基类名1 ...

  3. C++中虚基类在派生类中的内存布局

    今天重温C++的知识,当看到虚基类这点的时候,那时候也没有太过追究,就是知道虚基类是消除了类继承之间的二义性问题而已,可是很是好奇,它是怎么消除的,内存布局是怎么分配的呢?于是就深入研究了一下,具体的 ...

  4. C++ 虚继承实现原理(虚基类表指针与虚基类表)

    虚继承和虚函数是完全无相关的两个概念. 虚继承是解决C++多重继承问题的一种手段,从不同途径继承来的同一基类,会在子类中存在多份拷贝.这将存在两个问题:其一,浪费存储空间:第二,存在二义性问题,通常可 ...

  5. C++:虚基类

    4.4.3 虚基类1.没什么要引入虚基类 如果一个类有多个直接基类,而这些直接基类又有一个共同的基类,则在最底层的派生类中会保留这个间接的共同基类数据成员的多分同名成员.在访问这些同名的成员时,必须在 ...

  6. C++学习之路—继承与派生(三):多重继承与虚基类

    (根据<C++程序设计>(谭浩强)整理,整理者:华科小涛,@http://www.cnblogs.com/hust-ghtao转载请注明) 多重继承是指一个派生类有两个或多个基类.例如,有 ...

  7. 【C++】继承(虚基类)

    类的继承与派生 面向对象技术强调软件的可重用性,这种重用性通过继承机制来实现.而在类的继承过程中,被重用的原有类称为基类,新创建的类称为派生类.派生类定义语法格式如下: class <派生类名& ...

  8. C/C++ 多继承{虚基类,虚继承,构造顺序,析构顺序}

    C/C++:一个基类继承和多个基类继承的区别 1.对多个基类继承会出现类之间嵌套时出现的同名问题,如果同名变量或者函数出现不在同一层次,则底层派生隐藏外层比如继承基类的同名变量和函数,不会出现二义性, ...

  9. C#虚基类继承与接口的区别

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

随机推荐

  1. merge into报错ORA-00926、ORA-38014

    今天用ibatis写个插入操作,为了兼容修改想使用 merge into语句,以便重复插入时直接 update,具体语句如下: <insert id="wlf"> ME ...

  2. .NET泛型与非泛型的问题

    泛型集合通常情况下,建议您使用泛型集合,因为这样可以获得类型安全的直接优点而不需要从基集合类型派生并实现类型特定的成员.下面的泛型类型对应于现有的集合类型:1.List 是对应于 ArrayList ...

  3. mysql索引之六:mysql高效索引之覆盖索引

    概念 如果索引包含所有满足查询需要的数据的索引成为覆盖索引(Covering Index),也就是平时所说的不需要回表操作 判断标准 使用explain,可以通过输出的extra列来判断,对于一个索引 ...

  4. 圆周率的现代计算机求法(C语言) Lebal:research

    C语言求圆周率π 公式法1 #include <stdio.h> #include <math.h> int main(){ float term,result=1; int ...

  5. 字符编码py2,py3操作,SecureCRT的会话编码的设置

    对之前的字符串类型和二进制类型(bytes类型),可以这样关联记忆,把字符串类型当作是Unicode,把bytes类型当作是GBK或者UTF-8或者是日文编码.这样字符串要转成二进制,那么就需要编码e ...

  6. sublime text3 自动编译php 适合用于简单的php文件执行

    1.将php路径放入环境变量中 2. 点击 sublime_text的“工具”->"编译系统"->"编译新系统" { "cmd" ...

  7. 20181102_WCF简单双工

    使用管理员权限打开VS2017 2. 创建一个空白解决方案: 3. 创建几个基于.net  framework的类库项目和一个基于.net Framework 的控制台项目, 然后将类库项目的clas ...

  8. Docker - 避免启动container后运行shell脚本执行完成后docker退出container

    问题 最近在使用 Dockerfile 启动容器,发现使用Dockerfile调用容器里面的shell,当shell执行完成以后,docker会退出容器. 分析 Docker 在执行shell的时候, ...

  9. 第13章 Spring框架的设计理念与设计模式分析

    13.1 Spring的骨骼架构 最核心的组件是:Core, Context, Bean. 13.1.1 Spring的设计理念 Spring最核心的组件是Bean组件.Spring解决的最关键的问题 ...

  10. 分布式队列 Celery

    详情参见: 分布式队列神器 Celery 用户指南(User Guide) 1) Celery-4.1 用户指南: Application(应用) 2) Celery-4.1 用户指南: Task(任 ...