c++继承


一、什么是继承?

百度百科:利用已有的数据类型来定义新的数据类型

通过继承机制,可以利用已有的数据类型来定义新的数据类型。所定义的新的数据类型不仅拥有新定义的成员,而且还同时拥有旧的成员。我们称已存在的用来派生新类的类为基类,又称为父类。由已存在的类派生出的新类称为派生类,又称为子类

一般形式

class 子类名:继承方式 父类名

二、继承中的权限变化

继承父类中的数据,以不同的方式继承会改变父类原有数据在子类中的权限。只改变数据在子类中的权限,不改变父类原有权限

  1. 以public的方式继承
class ChildClass:public FatherClass

不改变权限。父类中private下的数据继承到子类中也是private,protected和public下的也一样。

  1. 以protected继承
class ChildClass:protected FatherClass

只改变父类中的public数据权限。将父类中public权限的数据变成protected后继承到子类中,其它数据不变。

  1. 以private继承
class ChildClass:private FatherClass

所有数据都以private的方式继承。子类中所有在父类中继承的数据都改为private权限。

三、继承中的构造函数

子类需要调用父类构造函数初始化数据(或者父类中有无参构造则不用)。

class FatherClass
{
public:
	FatherClass(int num) { m_Fnum = num; }
	int m_Fnum;
};

class ChildFather :public FatherClass
{
public:
	ChildFather(int n) :FatherClass(n) {}			//用n初始化继承下来的m_Fnum
};

四、继承的其它形式

  1. 多继承

大多数使用继承都是单继承(上面的例子就是单继承),还有多继承。
多继承:两个以上的父类

class ChildClass:public FatherClass1, FatherClass2
{
public:
	ChildClass(int num) :FatherClass1(num),FatherClass2(num) {}
};

多个继承用","隔开。

  1. 菱形继承
    为了解决从两个父类汇总继承相同属性的二义性。
    比如,FatherClass1中有个属性m_Fnum,FatherClass2中也刚好有个同名的m_Fnum(一般是两个父类继承了相同的类造成的),那么,ChildClass在使用这个属性时就会不明确
class GrandFatherClass									//祖父类
{
public:
	GrandFatherClass(int Gnum) { m_Gnum = Gnum; }
	int m_Gnum;
};
class FatherClass1:virtual public GrandFatherClass		//父类,虚继承
{
public:
	FatherClass1(int Fnum1):GrandFatherClass(Fnum1) {}
};

class FatherClass2 :virtual public GrandFatherClass		//父类,虚继承
{
public:
	FatherClass2(int Fnum2) :GrandFatherClass(Fnum2) {}
};

class ChildClass:public FatherClass1, FatherClass2		//子类
{
public:														//所有继承的构造函数都要调用
	ChildClass(int num) :GrandFatherClass(num),FatherClass1(num), FatherClass2(num){}
};

FatherClass1和FatherClass2 继承GrandFatherClass类,ChildClass 又继承FatherClass1和FatherClass2类,就像一个菱形一样。

例子中,本来FatherClass1, FatherClass2都继承了GrandFatherClass,只有一份m_Gnum,ChildClass 又分别继承了FatherClass1, FatherClass2,应该有两份m_Gnum产生二义性,但是FatherClass1, FatherClass2使用的是virtual虚继承,并不会像原来那样把两份直接继承下来,而是只留一份,也可以看成是从GrandFatherClass中继承下来的。

最后数据的值,由参数列表中GrandFatherClass的初始化值决定。

注意:要调用间接继承的GrandFatherClass类的构造函数,同时也要调用直接继承的两个类的构造函数。

五、其它

  1. 同名问题(二义性)
    就近原则。当子类中出现和父类同名的属性时,子类创建的对象使用子类中的属性,父类创建的对象使用父类中的属性。

  2. 指针访问

ChildClass* pC = new ChildClass(1);
  1. 上行转换
    用子类初始化父类,因为子类调用了父类的构造函数,实际上是可行的有初始化数据的。
FatherClass1* pB = new ChildClass(1);

因为是FatherClass1类,使用的是FatherClass1中的数据,没有子类的属性。

4.下行转换、交叉转换
一般情况下不被允许,强行使用需要static_cast、dynamic_cast等手段转。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小冯爱编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值