C++继承
来源:互联网 发布:石油进出口数据 编辑:程序博客网 时间:2024/06/17 04:26
继承概念
继承是面向对象程序设计使代码可以复用的重要手段,在保持类原有特征的基础上,对类进行扩充,增加新的功能,以此产生一个新类,这就是继承。原有类叫做基类(父类),新产生的类叫做派生类(子类)。
继承定义格式
class 派生类名:继承方式 基类名
例如:
class Student:public Person
继承方式
类的成员访问限定符有三种:public(公有),protected(保护),private(私有),继承方式也是这三种。
- 三种继承关系下基类成员在派生类的访问关系变化
其实只要两句话就很容易记住这张表
1. 不论哪种继承方式,private成员都不可见(不能访问)
2. 列表内容成员权限不能超过继承方法权限(public>protect>private)
分析一下第二句话,因为private成员始终不可见,所以我们只用讨论public成员和protect成员在不同继承方式下的情况就好了。
如果是public继承方式,public成员和protect成员的权限都没有超过public,所以继承后类型不变,public成员仍为public,protect成员仍为protect
如果是protect继承,public成员权限超过了protect,就要变成protect类型,而protect成员没有超过protect,类型不变,仍为protect
如果是private继承,public成员和protect成员权限都超过了private,全部变为private
继承关系中构造和析构函数的调用顺序
- 构造函数:
基类构造函数(按照继承列表中的顺序)——>派生类中对象构造函数(按照派生类中声明顺序)——>派生类构造函数
假设A1,A2,B1,B2是几个不相关的类,将A1,A2作为父类继承产生一个新类C,并且将B1,B2整个作为C的成员变量,那么当我们C来实例化一个对象c时,首先调用A1和A2的构造函数(继承列表中A1在前就先调A1,A2在前就先调A2),然后是B1和B2的构造函数(先声明B1就先调B1,先声明B2就先调B2),最后才调用C自己的构造函数。 - 析构函数与构造函数相反:
派生类析构函数——>派生类包含成员对象析构函数(调用顺序与成员对象在类中声明顺序相反)——>基类析构函数(调用顺序与基类在派生类列表中声明顺序相反)
继承体系的作用域
- 在继承体系中基类和派生类是两个不同的作用域
- 子类和父类中有同名成员,子类成员会屏蔽父类对成员的直接访问(在子类成员函数中,可以使用 基类::基类成员 访问)
- 在继承体系里最好不要定义同名的成员
class A{public: void a() { cout<<'A'<<endl; }};class B:public A{public: void a() { cout<<'B'<<endl; }};void test(){ B b; b.a(); b.A::a();}
运行结果:
B
A
请按任意键继续…
赋值兼容规则
- 子类对象可以赋值给父类对象(切割/切片)
- 父类对象不能赋值给子类对象
- 父类的指针/引用可以指向子类对象
- 子类的指针/引用不能指向父类对象
要使父类指针指向子类对象,只需让它指向子类继承父类部分的首地址,就可以用它来访问子类中从父类继承来的部分,因为父类指针只能访问父类大小的空间,所以用父类指针指向子类对象时无法利用此指针访问子类新增部分。
如果用子类指针指向父类对象,子类指针会访问子类个大小的空间,就会访问到不属于这个类的空间,形成越界访问,所以不允许用子类指针指向父类对象。
继承与静态成员
基类定义了static成员,则整个继承体系里都只有一个这样的成员,无论派生多少个子类,都只有一个这样的static成员实例。
单继承&多继承&菱形继承
单继承
一个子类只有一个直接父类多继承
一个子类有两个以上的直接父类- 菱形继承
举个例子
class T{public: int _a;};class L:public T{};class R:public T{};class D:public L,public R{};void Test(){ D d; d._a=1;}
运行时编译器会报错:
1>—— 已启动生成: 项目: 继承, 配置: Debug Win32 ——
1>正在编译…
1>test.cpp
1>f:\vs项目\继承\继承\test.cpp(22) : error C2385: 对“_a”的访问不明确
1> 可能是“_a”(位于基“T”中)
1> 也可能是“_a”(位于基“T”中)
1>生成日志保存在“file://f:\vs项目\继承\继承\Debug\BuildLog.htm”
1>继承 - 1 个错误,0 个警告
========== 生成: 成功 0 个,失败 1 个,最新 0 个,跳过 0 个 ==========
这个错误是因为d中有两份_a,编译器不知道该给哪个_a赋值,将d._a=1改为
d.L::_a=1; d.R::_a=0;
这样程序就可以正常运行
调试这段代码发现d中确实有两份_a,位于不同的作用域中,分别有着自己的内存地址和值。
因为菱形继承存在二义性和数据冗余的问题,所以尽量不要用菱形结构体系。
- c继承
- C++----------------继承
- 【c#】继承
- C++:继承
- C++::继承
- [C++]继承
- 【C++】继承
- 【C#】继承
- 【c++】继承
- 【C++】继承
- c#-继承
- 【C++】 继承
- 【C#】继承
- C++|继承
- 【C++】继承
- C/C++--私有继承
- [C/C++]继承
- c++:私有继承,公有继承,保护继承
- 受欢迎的牛bzoj1051(浅谈tarjan——(3))
- Fragment+ViewPage一步步实现底部导航栏。
- 在V4中如何使用局部时钟网络
- paxos算法结合Zookeeper介绍
- 浅谈在java中list集合的排序问题
- C++继承
- [转载]Spring Cloud在国内中小型公司能用起来吗?
- LINUX 查看版本信息
- Python中的装饰器
- 任发科:DevOps的前世来生,从《目标》、《凤凰项目》到《持续交付》
- 删除指定目录下的全部文件或文件夹
- GIT本地服务端搭建顺序
- [转载]中小型互联网公司微服务实践-经验和教训
- Algorithm-week8