c++继承

目录

一、继承格式

二、子类对父类的权限

​1、private

2、protect

3、public

总结:

三、 struct和class继承区别

四、赋值兼容

五、继承中的作用域

1、子父类的作用域是独立的

2、子父有相同成员:隐藏

3、怎么访问父类?

六、继承类的默认成员函数

1、构造

2、拷贝构造

3、赋值重载

4、析构函数

5、静态成员的继承

总结

七、单继承和多继承

1、菱形继承问题

2、如何解决菱形继承—虚继承

3、总结

八、组合与继承(优先使用组合)

1、低耦合和高内聚


一、继承格式


class son public: father

二、子类对父类的权限


1、private

子类不可直接访问
但是子类可以间接使用
例如调父类的get函数
 

2、protect

在类外面不能访问
但是子类可以访问

3、public

子类和父类的权限比较,那个小就取那个
例如子类为public方式继承,但是父类的A函数为protect
那么,最终子类对A函数的权限就是protect

总结:

父类的private子类都不能用,其余public和protect要和子类的继承方式比较,那个小取那个

三、 struct和class继承区别

struct默认继承方式和访问限定符都是共有
class默认继承方式和访问限定符都是私有
 

四、赋值兼容

类型相近的类型可以互相转换
例如,int和double可以互相转换
同理,依照上述例子,子类对象也可以赋值给父类对象
子类在public继承的情况下,子类可以转化为父类类型
可以理解为每个子类对象都是一个特殊的父类对象
怎么给?
共有的部分赋值给父类
但是子类独有的部分不会给到父类对象
这个过程叫做切割/切片
期间不产生临时变量
但是,父不能给子
很好理解
因为有些东西子类有,但是父类没有,无法赋值
 

五、继承中的作用域

1、子父类的作用域是独立的

因此不构成函数重载

2、子父有相同成员:隐藏

访问的是子类的,就近原则
子类会把父类的同名成员屏蔽,这种情况叫做隐藏

3、怎么访问父类?

指定作用域访问
子类对象指定访问父类域内的成员

son.father::father_func();

如果子类直接访问父类的成员,而没有指定类域,就会导致编译错误
因为子类域内找不到,但是你又没有告诉我要到那个域去找,所以我不知道,所以报错

六、继承类的默认成员函数

1、构造

子类的默认构造怎么处理父类?
子类分成了两个部分:
一个是父类,将父类看成一个类
一个是子类本身,内置类型不处理,自定义类型调用对应的构造

也就是说,如果子类在初始化的时候
会调用父类的默认构造
剩下的部分要调用子类自己的默认构造

但是,如果父类没有自己的默认构造,子类也会报错
相当于,子类的一个自定义类型没有其对应的默认构造
派生类一定会去调用父类的构造,因为要继承
这一块很简单,父类就是子类的一个自定义对象

2、拷贝构造

和构造相同
将父类视为一个简单的自定义类型
仅此而已
因此不需要自己写
但是如果要深拷贝,就要自己写

3、赋值重载

例如是operator=运算符重载
子类和父类都有一个,要注意构成隐藏
如果要调用父类的operator=需要指定域访问 

4、析构函数

如果是自定义的析构,也会构成隐藏
但是,子类析构结束后,会自动调用父类析构函数
但是还是可以显式指定域访问父类析构
虽然析构函数看起来名字不相同,属于各自的类

5、静态成员的继承

父类的静态成员只有一份
所有的子类都共用这一个静态成员

总结

原则:
构造保证先父后子
析构保证先子后父
常见复用的体现:
1)函数逻辑的复用
2)模板的复用
3)继承的复用


七、单继承和多继承

单继承:只有一个直接父类
多继承:两个及以上的直接父类

1、菱形继承问题

什么叫做菱形问题?
这个问题是从继承区分单继承和多继承这个特性上衍生出来的
例如下面这个图:

那么,在这种情况下,这个D就会继承有Base的成员
这就是菱形问题:
a、数据冗余
b、数据二义性,访问错误,因为不知道到底访问的是谁的

2、如何解决菱形继承—虚继承

用关键字virtual解决(其实已经涉及到多态了)
格式:

virtual void func() {}

看一个具体例子:
 

#include<iostream>
using namespace std;

//grand
class grand
{
public:
	virtual void func()//父类必须加vitual,加了vitual关键字,就叫做虚函数
	{
		cout << "grand->func" << endl;
	}

private:
	int _grand;
};


//父类(基类)
class father1 : public grand
{
public:
	virtual void func()//父类必须加vitual,加了vitual关键字,就叫做虚函数
	{
		cout << "father1->func" << endl;
	}

private:
	int _father1;
};

//父类(基类)
class father2 : public grand
{
public:
	virtual void func()//父类必须加vitual,加了vitual关键字,就叫做虚函数
	{
		cout << "father2->func" << endl;
	}

private:
	int _father2;
};


/子、父类虚函数,函数名相等,返回值相同,参数相同,构成重写

//子类(派生类)
class son : public father1 ,public father2
{
public:
	virtual void func() //子类可以不加vitual,但是建议加上
	{
		cout << "son->func" << endl;
	}

private:
	int _son;
};



int main()
{
	grand g;
	father1 f1;
	father2 f2;
	son s;

	g.func();
	f1.func();
	f2.func();
	s.func();



}

这个可以重点理解一下
底层如何解决?可以看另一篇博主的文章


3、总结

在实践中,可以设计多继承
但是不要设计出菱形继承的结构
(iostream的io流就是使用菱形继承)

菱形继承是在2.0版本出现的
到了3.0才出现的
既然会出现歧义问题
为什么不删掉呢?
因为要兼容以前的历史版本,即向前兼容
所以,只有解决,不能删除
所以,尽管付出了解决的代价,即大大的增加的了设计的复杂度
但是,这是必须要付出的代价
这也是历史发展的包袱,历史发展的惯性,历史发展的代价

八、组合与继承(优先使用组合)

1、低耦合和高内聚

低耦合就是模块之间、类之间的联系低,互相影响程度低
例如说,人类和石头类,联系程度低,二者的组合就是低耦合
但是也是分使用场景

高内聚就是一个类内部的各种数据要尽可能的关联度紧密
例如,一个人对象的类,对于发量、交往对象的信息数据来说,大多数场景下,不是那么必要
所以,不是高内聚
而姓名、性别、年龄等信息就和人这个类关系紧密
继承耦合度高、组合耦合度低
耦合度低维护性更好
这个很好理解,因为组合相对于继承来说,类之间的紧密程度更低,关联影响更低
所以耦合度就低,耦合度低,容错率就高,更加稳定

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

二十5画生

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

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

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

打赏作者

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

抵扣说明:

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

余额充值