继承

  类和类的关系有组合、继承和代理。继承的本质就是代码复用。子类继承父类中的一些东西,父类也称为基类,子类也称为派生类。派生类继承了基类除构造函数以外的所有成员。

继承的方式

  继承方式有public(公有继承)、private(私有继承)和protected(保护继承)。基类中不同访问限定符下(public、protected、private)的成员以不同的继承方式继承,在派生类中的访问限定也不同,具体如下:

基类的布局优先于派生类
#include<iostream>
class Base
{public:Base(int a):ma(a){}
public:int ma;
};
class Derive :public Base
{public:Derive(int b):mb(b), Base(b){}
public:int mb;
};
int main()
{Derive(20);return 0;
}

  我们可以在开发人员命令提示符窗口中进入当前源文件的目录,使用cl ConsoleApplication5.cpp /d1reportSingleClassLayoutDerive来查看派生类Derive的布局如下:

由图可见,基类的布局优先级高于派生类。那么派生对象的构造方式是怎么样的呢?
1.调用基类的构造函数
2.调用派生类的构造函数
派生类的析构可想而知:
1.调用派生类的析构函数
2.调用基类的析构函数

虚函数

如下程序:

class Base
{public:Base(int a):ma(a){}virtual void Show(){std::cout << "Base:Show  ma=" << ma << std::endl;}
protected:int ma;
};
class Derive :public Base
{public:Derive(int b):mb(b), Base(b){}void Show(){std::cout << "Derive:Show  mb=" << mb << std::endl;}
protected:int mb;
};
int main()
{std::cout << "sizeof(Base):" << sizeof(Base) << std::endl;std::cout << "sizeof(Derive):" << sizeof(Derive) << std::endl;Base* pb=new Derive(20);std::cout << typeid(pb).name()  << std::endl;std::cout << typeid(*pb).name() << std::endl;pb->Show();return 0;
}

运行结果如下:

  上面结果说明一个基类的指针是可以指向其派生类对象的。基类中含有虚函数,那么基类布局中存在一个虚函数指针,指向虚函数表;且其派生类中与其同名同参的函数不需要加virtual也是虚函数。此时基类和派生类的布局如下:


  vfptr的指针大小为4(32位机器)。因此基类字节数为8,派生类为12。vfptr指针指向的vftable(虚函数表)中,&Base_meta中存放了RTTI信息(运行时类型信息),也就是class Base,0表示偏移,&Base::Show表示虚函数的入口地址。typeid()可以动态获取类型。
  main函数中,生成了一个派生类对象。pb是一个指针类型,它的类型只和定义点有关,因此打印出来pb的类型为class Base类型;而pb是一个自定义类型,动态获取类型时,先通过指针pb解引用找到派生类对象,通过vfptr找到vftable,&Derive_meta中存放了派生类的RTTI信息,其中存放的是class Derive,因此*pb的类型是class Derive。
  pb指针调用Show()函数时,发生了动多态。首先通过指针所指向的对象找到vfptr,再找到vftable,获取到Show函数的入口地址,此时 &Derive::Show中存放的是派生类的虚函数入口地址,因此调用的是派生类中的Show()函数。

c++继承 基类 派生类 虚函数相关推荐

  1. C++之继承探究(十):抽象基类与纯虚函数

    前文:C++之继承探究(九):多态的代价 抽象基类与纯虚函数   ♠\spadesuit♠ 纯虚函数:虚函数只有声明,函数体=0,就是一个纯虚函数,纯虚函数没有函数体,不需要实现.在子类里实现纯虚函数 ...

  2. C++ day24 继承(四)抽象基类,纯虚函数,protected

    文章目录 关键字protected(带来方便同时带来危险,最好不用) 抽象基类和纯虚函数(is-a关系用公有继承实现有时候也不太合适) 用圆和椭圆的笨拙派生为例,挑拨is-a和公有继承的搭档关系 替代 ...

  3. 避免在派生类中重新定义基类的非虚函数

    我们都知道,在基类中定义虚函数的目的是允许派生类拥有相同接口却可以有不同的实现,通过对象的指针或引用来访问虚函数可以实现运行时的多态.这么说来,在派生类中重定义(override)虚函数是没有任何问题 ...

  4. C++中虚继承产生的虚基类指针和虚基类表,虚函数产生的虚函数指针和虚函数表

    本博客主要通过查看类的内容的变化,深入探讨有关虚指针和虚表的问题. 一.虚继承产生的虚基类表指针和虚基类表 如下代码:写一个棱形继承,父类Base,子类Son1和Son2虚继承Base,又来一个类Gr ...

  5. C++中为什么要引入抽象基类和纯虚函数?

    为什么要引入抽象基类和纯虚函数? 主要目的是为了实现一种接口的效果. 抽象类是一种特殊的类,它是为了抽象和设计的目的为建立的,它处于继承层次结构的较上层. ⑴抽象类的定义:带有纯虚函数的类为抽象类. ...

  6. C++之抽象基类与纯虚函数

    // Vitual_Base.cpp : Defines the entry point for the console application. //抽象基类与纯虚函数#include " ...

  7. C++引入抽象基类和纯虚函数的作用和目的

    为什么要引入抽象基类和纯虚函数? 主要目的是为了实现一种接口的效果. 原文链接:https://blog.csdn.net/weibo1230123/article/details/82014322 ...

  8. C++学习笔记-----永远不要在派生类中改变虚函数的默认参数值

    提到虚函数,我们就会自然而然的想到多态,但是当虚函数中存有默认参数值的时候,在派生类中重定义这个虚函数时不可以改变这个参数的值. 请看下面的例子: #include "stdafx.h&qu ...

  9. 807-C++多继承下,派生类对象有几张虚函数表?

    C++多继承下,派生类对象有几张虚函数表? 我们看下面这个示例: #include <iostream> #include <string> #include <type ...

最新文章

  1. NTP时间服务器简介
  2. gitlab合并分支_GitLab-参考问题
  3. easyUi创建临时Dialog
  4. boost::hana::test::TestSearchable用法的测试程序
  5. objective-c高级编程 笔记
  6. javascript --- 瀑布流的实现
  7. Selleck --- 01Cookie
  8. C++异常以及错误处理
  9. IntelliJ IDEA2017 java连接mysql数据库并查询数据
  10. 牛客寒假算法基础训练营5
  11. java layer调用native层的android_media_AudioTrack_get_min_buff_size()确定audio track buffer的min size...
  12. Mysql update 语句(chm文档)
  13. 如何用Matlab计算相关系数和偏相关系数
  14. 安装装ankhsvn
  15. Backdoor Attack with Imperceptible Input and Latent Modification
  16. Unity ProjectTiny用纯ECS写个跃动的小球
  17. 秦岚微博之夜喜提热搜第一 优雅公主裙演绎真人版辛德瑞拉
  18. AriaNG保存服务器信息,安装Aria2+AriaNg
  19. 第一天之导入Vuetify的坑
  20. java pdf替换内容_Java添加、提取、替换和删除PDF图片

热门文章

  1. 多径信道下通过LMS均衡算法提高通信质量——详细版
  2. 最常用算法汇总(一)
  3. 4.基于NIO的群聊系统
  4. python实现离散点图画法
  5. python:matplotlib.pyplot绘制散点图(基础一)
  6. Tomcat 乱码问题解决方法
  7. docker多容器操作与强制删除容器的方法步骤
  8. e2e 测试 出现的错误
  9. 一元函数的导数与微分概念及其计算
  10. 什么是大数据lambda架构