c++继承
来源:互联网 发布:elton john知乎 编辑:程序博客网 时间:2024/06/11 12:37
什么是继承
继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能。
继承的语法
在代码中和原来一样给出该类的名字,但在类的左括号前面,加上一个冒号和基类的名字(多重继承基类名用逗号分开)
继承的关系
对私有继承成员公有化
当私有继承时所有的public成员都变成了private,如果希望它们中任何一个是可视的,只需要用派生类的public部分生命他们的名字即可。
c语言实现继承
/// \file inherit.c/// \brief/// \author suntangji, suntangj2016i@gmail.com/// \version 1.0/// \date 2017-11-24#include<stdio.h>#include<malloc.h>struct Base { int b; void (*pfb)(); /*c语言不支持结构体内部定义函数,所以使用函数指针 */};struct Derived { int d; void (*pfd)(); struct Base* base;};void FunBase() { printf("Base::FunBase");}void FunDerived() { printf("Derived::FunDerived");}struct Base* NewBase(){ struct Base* pb = (struct Base*)(malloc(sizeof(struct Base))); pb->b = 0; pb->pfb = FunBase; return pb;}struct Derived* NewDerived(){ struct Derived* pd = (struct Derived*)(malloc(sizeof(struct Derived))); pd->d = 0; pd->pfd = FunDerived; pd->base = NewBase(); return pd;}int main() { struct Base * b = NewBase(); struct Derived * d = NewDerived(); b->pfb(); d->pfd(); d->base->pfb(); return 0;}
C语言实现的缺陷
- 没有继承关系
- 没有构造函数和析构函数容易造成内存泄露
- 函数调用比较麻烦
构造函数的调用顺序
先调用派生类的构造函数,在派生类构造函数参数列表中调用基类的构造函数,然后在构造派生类自己的成员。
析构函数的调用顺序
先调用派生类的析构函数,再调用基类的析构函数。
同名隐藏与重写
当基类的成员函数不是虚函数时,派生类和它有同名的函数时(函数原型可以不同)会隐藏基类的函数。当基类的成员函数是虚函数时,派生类有和基类同名的函数(函数原型需要相同)会发生重写。
向上类型转换
- 派生类对象可以赋值给基类对象
- 基类对象不可以赋值给派生类对象
- 基类对象的指针/引用可以指向派生类对象,但不能访问派生类对象可以访问基类对象
- 派生类对象的指针/引用不可以指向基类对象(强制类型转换后可以)
非自动继承的函数
- 构造函数
- 析构函数
- 赋值运算符重载
单继承的对象模型
基类的成员在上(低地址),派生类的成员在下(高地址)
多继承的对象模型
最先继承的基类在上(低地址),其次继承的基类在下(高地址),派生类的成员在最下(低地址)
菱形继承的对象模型
class Base {public: Base() { _b = 1; }private: int _b;};class C1:public Base{public: C1() { _c1= 2; }private: int _c1;};class C2 :public Base{public: C2() { _c2 = 3; }private: int _c2;};class Derived :public C1,public C2{public: Derived() { _d = 4; }private: int _d;};
这段代码在内存中存储是1 2 1 3 4
可以看出仍然是派生类的成员在下,基类的成员在上,只是基类又是其他基类的派生类。菱形继承对最上层的基类继承了2次,既造成了二义性又浪费了空间。
虚拟继承
虚拟继承可以解决菱形继承二义性的问题
class Base {public: Base() { _b = 1; }private: int _b;};class C1:virtual public Base{public: C1() { _c1= 2; }private: int _c1;};class C2 :virtual public Base{public: C2() { _c2 = 3; }private: int _c2;};class Derived :public C1,public C2{public: Derived() { _d = 4; }private: int _d;};
对象d的内存布局
0x0115FD44   e8 8b db 00
0x0115FD48   02 00 00 00
0x0115FD4C   f0 8b db 00
0x0115FD50   03 00 00 00
0x0115FD54   04 00 00 00
0x0115FD58   01 00 00 00
虚拟继承解决了菱形继承的二义性问题,因为菱形继承不再保存两份基类的变量,在对象内存的最高地址保存虚拟继承的基类成员,原来保存成员的地方保存了一个虚基类表格地址,该地址存储了2个变量,分别是相对自己的偏移量0和相对别虚拟继承的基类成员的偏移量。有了这两个偏移量就可以找到唯一一个基类成员,继而解决了菱形继承的二义性问题。
- c继承
- C++----------------继承
- 【c#】继承
- C++:继承
- C++::继承
- [C++]继承
- 【C++】继承
- 【C#】继承
- 【c++】继承
- 【C++】继承
- c#-继承
- 【C++】 继承
- 【C#】继承
- C++|继承
- 【C++】继承
- C/C++--私有继承
- [C/C++]继承
- c++:私有继承,公有继承,保护继承
- Linux进行yum 程序安装时遇到的公钥没有安装的问题解决方法
- 解决Git报错:error: You have not concluded your merge (MERGE_HEAD exists).
- 10、Android开发基础之点击事件的处理
- JQuery EasyUI与EXTjs有什么区别?
- java web项目生成二维码思想
- c++继承
- Xcoed 添加自定义docset文档
- SpringMVC参数校验,包括JavaBean和基本类型的校验(转载)
- 我的日志分析之道:简单的Web日志分析脚本
- 自实现链表的相关操作
- mac dyld:未加载库 dyld: Library not loaded: /usr/local/opt/jpeg/lib/libjpeg.8.dylib
- 注解没有注入
- 在pycharm中切换python版本的方法
- quartz(一):quartz简介及使用