C++中的继承和多继承
一、学习笔记
1.继承
class Student : public Person {
...
}
2.继承时权限
派生类中可以直接访问父类的protected成员,但是不能访问其private成员,若继承时不写public,默认就是private继承。
继承方式\基类中的访问属性 public protected private
public public protected 隔离
protected protected protected 隔离
private private private 隔离
(1) 无论哪种继承方式,在派生类的内部使用父类时并无差别
(2) 不同的继承方式,会影响这两方面:外部代码对派生类的使用,派生类的子类对派生类成员的使用。
3.using更改继承成员的权限
①修改成员变量的
在派生类中的public:下使用using Father::room_key;可以将父类的protected成员room_key提升为public权限,此时可以直接在main()中访问!
在派生类中的private:下使用using Father::room_key;可以将父类的protected成员room_key降低为private权限,此时就不可以在类外进行访问!
若在派生类中可以使用using关键字将父类的public成员降为private权限,这样子类的子类就继承不到这个属性了。
①修改成员函数的
在派生类中的public:下使用using Father::getRoomKey;可以将父类的protected成员getRoomKey()成员函数提升为public权限。可以直接使用函数名而不是
函数签名的原因是这里仅仅是修改权限,父类重载的所有getRoomKey()都变为public了,之后类外调用根据参数匹配规则不变。
也就是说可以使用using关键字调整继承来的成员的访问权限,但前提是这些成员对你这个类可见。
4.构造函数子类也会继承父类的,但是其构造的是从父类那里继承过来的部分。
5.子类中若是实现了与父类的同名函数getName(),可以Parent::getName()来调用父类的getName(), 但是操作的成员变量是子类继承父类的部分。
6.子类定义与继承来的可见的成员变量同名的成员变量也是可以的。重新定义函数签名和函数名都相同的函数叫做复写。
7.继承的父类的成员函数中操作的成员变量都是子类继承于父类的。父类的成员函数操作的成员变量都是父类的,除非子类进行了复写。
8.在子类的外部可以通过s1.Father::getRoomKey();调用父类的函数,在子类的内部可以通过Father::getRoomKey();调用父类的函数。
9.多重继承
class Sofabed: public Sofa, public Bed {
...
} Sofabed s;
s::Sofa::setWeight() //指明调用Sofa的setWeight()
10.多继承会导致二义性,解决办法是使用虚继承。
解决:把共性的东西提炼出来,只保留一份备份,放在共有的父类Fourniture中,然后Sofa和Bed都虚继承Fourniture。
class Sofa : virtual public Fourniture
class Bed : virtual public Fourniture
class Sofabed: public Sofa, public Bed
11.虚继承内存分布
虚继承的成员在Sofabed类中只会保留一份备份,也就是说Fourniture类中定义的成员只会在SofaBed类中只保留一份。
12.要尽量避免使用多继承,它会使程序变得更加复杂,更容易出错。
13.带有继承和虚继承的构造函数的调用次序
先父后子:
(1)先调用基类的构造函数
①先调用虚拟基类的构造函数,再调用一般基类的构造函数。注意是先把所有虚基类的构造函数执行完后再执行的一般基类的构造函数。
(2)然后再调用自身的构造函数
①先调用对象成员的构造函数,然后再调用自己的构造函数。
对于虚继承的基类,基类的构造函数只执行一次。
eg: 如下两次继承,Furniture和Verication3C,它两个的构造函数是被调用一次!
class Soft : virtual public Furniture, virtual public Verication3C
class Bed : virtual public Furniture, virtual public Verication3C
14.子类的构造函数给父类的构造函数传参数
class LeftRightSofabed : public Sofabed, virtual public LeftRightCom {
private:
Date date;
public:
LeftRightSofabed(char *str1) : Sofabed(str1), LeftRightCom(str1), date(str1) { //注意这里的data用的是成员名,而不是类名
cout <<"LeftRightSofabed()"<<endl;
}
};
试验发现,在子类中使用初始化列表初始化虚继承的类无法触发虚继承的类中的有参构造函数被调用,调用的还是无参构造函数。
eg:上面代码中LeftRightCom()的有参构造函数不会被调用,调用的还是无参构造函数。
二、例子
1.单继承例子
#include <iostream> using namespace std; class Father {
private:
int money;
char *name;
protected:
int room_key; int getRoomKey(int) {
cout << "getRoomKey(int) name=" << name << endl;
return room_key;
}
public: int getRoomKey(void) {
cout << "getRoomKey(void) name=" << name << endl;
return room_key;
}
Father() {
money = ;
room_key = ;
name = "father_begin";
cout << "Father()" << endl;
}
Father(char *name) {
this->name = name;
cout << "Father(char *name)" << "name= " << this->name << endl;
}
~Father() {
cout << "~Father()" << endl;
} int getMoney(void) {
cout << "int getMoney(void)" << endl;
return money;
}
void setMoney(int money) {
cout << "void setMoney(int money)" << endl;
this->money = money;
}
}; class Son : public Father {
char *name; public:
using Father::room_key;
using Father::getRoomKey;
Son(char *name){
this->name = name;
cout << "Son()" << "name= " << this->name << endl;
}
~Son() {
cout << "~Son()" << "name= " << this->name << endl;
}
int getRoomKey(void) {
Father::getRoomKey();
cout << "getRoomKey(void) name=" << name << endl;
return room_key;
} }; int main()
{ Son s1("son_name"); s1.getRoomKey();
s1.getRoomKey();
s1.Father::getRoomKey();
s1.getMoney(); cout <<"s1.room_key= "<< s1.room_key << endl; return ;
} /*
Father()
Son()name= son_name
getRoomKey(void) name=father_begin
getRoomKey(void) name=son_name
getRoomKey(int) name=father_begin
getRoomKey(void) name=father_begin
int getMoney(void)
s1.room_key= 1
~Son()name= son_name
~Father()
*/
2.多继承中使用虚继承来处理成员变量二义性问题
#include <iostream> using namespace std; class Furniture {
int weight;
public:
int size;
int getWeight() {
cout << "Furniture::getWeight()" << endl;
return weight;
}
}; class Sofa : virtual public Furniture {
int sofa;
public:
void getSofa() {
cout << "Sofa::getSofa()" << endl;
}
}; class Bed : virtual public Furniture {
int bed;
public:
void getBed() {
cout << "Bed::getBed()" << endl;
}
}; class Sofabed : public Sofa, public Bed {
int color;
public:
int getColor() {
cout << "Sofabed::getColor()" << endl;
return color;
} int getSize() {
cout << "Sofabed::getSize()" << endl;
return size;
}
}; int main() { Sofa so;
Bed be;
Sofabed sb; so.getWeight();
so.getSofa(); be.getWeight();
be.getBed(); sb.getSize();
sb.getSofa();
sb.getBed();
sb.getWeight(); return ;
} /*
Furniture::getWeight()
Sofa::getSofa()
Furniture::getWeight()
Bed::getBed()
Sofabed::getSize()
Sofa::getSofa()
Bed::getBed()
Furniture::getWeight()
*/
3.虚继承构造函数中调用父类构造函数的例子
#include <iostream> using namespace std; class Furniture {
public:
Furniture() {
cout << "Furniture()" << endl;
}
Furniture(char *abc) {
cout << "Furniture(abc)" << endl;
}
}; class Verication3C {
public:
Verication3C() {
cout << "Verication3C()" << endl;
}
Verication3C(char *abc) {
cout << "Verication3C(abc)" << endl;
}
}; class Soft : virtual public Furniture, virtual public Verication3C {
public:
Soft() {
cout << "Soft()" << endl;
}
Soft(char *abc) : Furniture(abc), Verication3C(abc) {
cout << "Soft(abc)" << endl;
}
}; class Bed : virtual public Furniture, virtual public Verication3C {
public:
Bed() {
cout << "Bed()" << endl;
}
Bed(char *abc) : Furniture(abc), Verication3C(abc){
cout << "Bed(abc)" << endl;
}
}; class SoftBed : public Soft, public Bed {
public:
SoftBed() {
cout << "SoftBed()" << endl;
}
SoftBed(char *abc) : Soft(abc), Bed(abc){
cout << "SoftBed(abc)" << endl;
}
}; class LeightWrightCom {
public:
LeightWrightCom() {
cout << "LeightWrightCom()" << endl;
}
LeightWrightCom(char *abc) {
cout << "LeightWrightCom(abc)" << endl;
}
}; class Type {
public:
Type() {
cout << "Type()" << endl;
}
Type(char *abc) {
cout << "Type(abc)" << endl;
}
}; class Date {
public:
Date() {
cout << "Date()" << endl;
}
Date(char *abc) {
cout << "Date(abc)" << endl;
}
}; class LeightWrightSofaBed : public SoftBed, virtual public LeightWrightCom {
Type type;
Date date;
public:
LeightWrightSofaBed() {
cout << "LeightWrightSofaBed()" << endl;
}
LeightWrightSofaBed(char *abc) : SoftBed(abc), LeightWrightCom(abc), type(abc), date(abc) {
cout << "LeightWrightSofaBed(abc)" << endl;
}
}; int main()
{ LeightWrightSofaBed l1("lll"); return ;
} /*
Furniture() //没有调用有参构造函数!!
Verication3C() //没有调用有参构造函数!!
LeightWrightCom(abc) //调用了有参构造函数
Soft(abc)
Bed(abc)
SoftBed(abc)
Type(abc)
Date(abc)
LeightWrightSofaBed(abc)
*/
C++中的继承和多继承的更多相关文章
- C++中的多重继承与虚继承的问题
1.C++支持多重继承,但是一般情况下,建议使用单一继承. 类D继承自B类和C类,而B类和C类都继承自类A,因此出现下图所示情况: A A \ / B C ...
- HIbernate学习笔记(七) hibernate中的集合映射和继承映射
九. 集合映射 1. Set 2. List a) @OrderBy 注意:List与Set注解是一样的,就是把Set更改为List就可以了 private List< ...
- JS中通过call方法实现继承
原文:JS中通过call方法实现继承 讲解都写在注释里面了,有不对的地方请拍砖,谢谢! <html xmlns="http://www.w3.org/1999/xhtml"& ...
- Java中的集合类型的继承关系图
Java中的集合类型的继承关系图
- 盘点CSS中可以和不可以继承的属性
CSS中可以和不可以继承的属性 一.无继承性的属性 1.display:规定元素应该生成的框的类型 2.文本属性: vertical-align:垂直文本对齐 text-decoration:规定 ...
- 对Java中多态,封装,继承的认识(重要)
一.Java面向对象编程有三大特性:封装,继承,多态 在了解多态之前我觉得应该先了解一下 ...
- oc中protocol、category和继承的区别
OC中protocol.category和继承的区别以前还是有点迷糊,面试的时候说的有点混乱,现在结合一些资料总结一下. 利用继承,多态是一个很好的保持"对扩展开放.对更改封闭"( ...
- C++ 中私有继承、保护继承与公有继承
区别 下面通过一个示例来介绍三种继承的区别. 定义一个基类(假设为一个快退休的富豪): class RichMan { public: RichMan(); ~RichMan(); int m_com ...
- js中的对象创建与继承
对象创建 1.工厂模式 优点:解决了创建多个相似对象的问题 缺点:没有解决对象识别问题:每一个对象都有一套自己的函数,浪费资源 function createPerson(name, age, job ...
- Es5中的类和静态方法 继承
Es5中的类和静态方法 继承(原型链继承.对象冒充继承.原型链+对象冒充组合继承) // es5里面的类 //1.最简单的类 // function Person(){ // this.name='张 ...
随机推荐
- SqlServer2008备份与还原(完整图示版)
一.备份 1.在需要备份的数据库上,右键——任务——备份,如下: 2.选择备份到哪个路径和备份名字: 点击“添加”,如下, 3.上面点击“确定”后,回到第一个页面,选中刚才添加的路径和文件名 4.左上 ...
- 每天CSS学习之border-spacing
border-spacing是CSS2的一个属性.其作用是规定表格的相邻单元格边框之间的距离.如果表格的border-collapse属性值为collapse时,border-spacing设置无效. ...
- 在命令行中的vim编辑器加上行号
在使用vim编辑器时运行脚本程序纠察缺少相应的行号,检测起来非常不方便, 所以在vim编辑器每行前面加上相应的行号: 输入命令::set nu 按下回车,完成
- 1.4socket服务器打印信息的四种不同方式()
方式一 socker 服务器 # -*- coding: utf-8 -*- import sys,os,multiprocessing from socket import * serverHost ...
- 理解AXI Quad Serial Peripheral Interface(SPI) IP核
reference : PG153-AXI Quad SPI v3.2 LogiCORE IP Product Guide.pdf 在使用MicroBlaze过程中,调用了此IP,所以有必须仔细学 ...
- byte[]->new String(byte[]) -> getByte()引发的不一致问题
今天接短信接口,短信接口提供了sdk,我们可以直接用sdk发送请求然后发送对应短信. 但是想使用我们平台自定义的httpUtil实现. 然而忙了1天半,才解决这个问题,还是我同事帮忙找出问题并解决的. ...
- synchronized(七)
package com.bjsxt.base.sync006; /** * 死锁问题,在设计程序时就应该避免双方相互持有对方的锁的情况 * @author alienware * */public c ...
- nginx统计模块——ngx_http_stub_status_module
今天呢给大家分享一个nginx的统计模块的使用,这个模快我们是经常的使用呢,在我们对nginx最优化,调优的时候我们就需要借助这个模块去分析nginx的性能. 下面我们来看看这个模块的语法格式, 这个 ...
- django面试七
Dango model 几种继承形式抽共享继承不能等实例化,抽象方法必须在子类中实现,Django不对其建立对应的表.class Animal(models.Model): name = models ...
- java学习笔记5(方法)
方法: 1.如何创建方法 修饰符 返回值类型 方法名(参数){被封装的代码段} 2.方法的定义和使用的注意事项: a:方法不能定义在另一个方法里面: b:方法 名字和方法的参数列表,定义和调用时 ...