C++继承初阶(单继承)

声明:该博客所有结论全在vs2019下验证,不同编译器下所得结论会有些许差异

目录

什么是继承?

继承的定义格式以及规则

总结:

继承的赋值兼容规则(public继承权限下才有这个规则)

继承中的同名隐藏(也叫重定义) 

子类的默认函数

子类的构造函数

子类的拷贝构造函数

子类的赋值运算符重载 

子类的析构函数

 继承与静态成员变量

继承与友元


什么是继承?

继承机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原特性的基础上进行扩展,增加功能,这样产生新的类,称之为派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程,之前我们基础到的复用都是函数复用,继承是类设计层次的复用。

继承的定义格式以及规则

继承的定义格式:

 

不同的继承权限下子类的区别

基类的定义如下:

#include<iostream>
using namespace std;
class Base {
public:
	int a;
	void test1() {
		cout << "Base:this is public" << endl;
	}
protected:
	int b;
	void test2() {
		cout << "Base:this is protected" << endl;
	}
private:
	int c;
	void test3() {
		cout << "Base:this is private" << endl;
	}
};

public:

 即在public继承权限下,基类所有成员都被派生类继承;

在public继承权限下,我们在子类内可以直接访问基类中public 以及protected访问权限下的成员

虽然派生类继承了基类的私有成员,但是私有成员不能被直接访问。我们可以通过调用基类中的public 以及protected权限下的成员函数去间接访问。

在public继承权限下,我们在子类外只能直接访问父类中public访问权限下的成员。

相应的我们可以证明protected以及private继承权限下子类对基类的访问权限。

同时我们证明了在任意继承权限下,基类的所有成员都被基类继承。

总结:

类成员/继承方式 public继承 protected继承 private继承
基类的public成员 派生类的public成员 派生类的protected成
派生类的private成
基类的protected成
派生类的protected成
派生类的protected成
派生类的private成
基类的private成员 在派生类中不可见 在派生类中不可见 在派生类中不可见


1. 基类private成员在派生类中无论以什么方式继承都是不可见的。这里的不可见是指基类的私有成员还是被继承到了派生类对象中,但是语法上限制派生类对象不管在类里面还是类外面都不能去访问它。
2. 基类private成员在派生类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在派生类中能访问,就定义为protected。可以看出保护成员限定符是因继承才出现的。
3. 实际上面的表格我们进行一下总结会发现,基类的私有成员在子类都是不可见。基类的其他成员在子类的访问方式 == Min(成员在基类的访问限定符,继承方式),public > protected > private。
4. 使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的写出继承方式。                                                                                                                                  5.在实际运用中一般使用都是public继承,几乎很少使用protetced/private继承,也不提倡使用
protetced/private继承,因为protetced/private继承下来的成员都只能在派生类的类里面使用,实际中扩展维护性不强                                                                                                                                      6.struct定义的类的默认继承权限是public,class定义的类默认继承权限是private

继承的赋值兼容规则(public继承权限下才有这个规则)

可以使用基类对象对子类对象赋值(单向)


 

可以使用基类类型的指针指向子类的对象(单向),如果反向则需要强转:

 可以使用基类的引用引用子类的对象(单向)

public 继承方式下,子类和基类的关系我们可以看成子类是基类,但不能认为基类是子类。

 

继承中的同名隐藏(也叫重定义) 

概念:

基类和子类属于两个不同的作用域,如果基类中的成员与子类中的成员同名,自己会优先访问自己的,基类中的同名成员不能在子类对象中直接访问,我们把这种情况叫做同名隐藏。

我们可以通过加作用域限定符来访问base中的a成员变量 

 

注意,基类成员函数名如果和子类函数名相同,两者并不为函数重载关系,因为隶属的作用域都不相同,无法构成函数重载。成员函数的同名隐藏和成员变量相同这里不做赘述。

子类的默认函数

子类的构造函数

子类的构造函数必须调用基类的构造函数初始化基类那一部分成员。如果基类没有默认的构造函数,则必须要在子类构造函数的初始化列表阶段显式调用。

 该代码报错的原因是 在创建son对象时,基类没有合适的构造函数供子类调用,导致无法继承基类成员。   无法引用 "Inherit" 的默认构造函数  。

解决方法:显式定义子类构造函数,并在子类初始化列表调用基类的构造函数(由于a在Base中为私有成员,因而我这里给了a一个初值)

 

(波浪线是指我们没有初始化成员变量d,但我们编译可以通过 )

如果基类有默认的构造函数(无参构造函数以及全缺省构造函数),那么子类是否显式定义都可以编译通过看我们的具体需求。

子类的拷贝构造函数

子类的拷贝构造函数必须调用基类的拷贝构造函数完成基类部分的拷贝构造

如果子类不显示定义拷贝构造函数,则子类会自动调用基类的拷贝构造函数和自身的拷贝构造函数。拷贝方式为逐字节浅拷贝。

如果子类显式定义了拷贝构造函数,那么我们必须在子类的拷贝构造函数初始化列表显式调用基类的拷贝构造函数

 我们发现拷贝生成的son2的值和son的成员函数并不一样,原因:子类的拷贝构造函数没有调用基类的拷贝构造函数,因此子类调用了基类的默认构造函数来创建son2对象。解决方案,在拷贝构造初始化列表显式调用基类拷贝构造函数

子类的赋值运算符重载 

子类的operator=必须要调用基类的operator=完成基类的复制

如果子类没有定义运算符重载,那么编译器会自动给子类生成一个默认的赋值运算符重载函数,其赋值方式为浅拷贝。

 我们发现赋值运算出的son2与son并不相等,原因是在进行赋值操作时,只son中的成员d进行了赋值操作,解决办法:在子类赋值运算符重载中显式调用基类的赋值运算符重载函数。

子类的析构函数

派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才能保证派生类对象先清理派生类成员再清理基类成员的顺序

 

反汇编代码中,当~Inherit析执构函数函数体内命令行完毕,会自动调用基类中的基类析构函数来析构子类对象中继承的基类中的成员。 

 

 继承与静态成员变量

基类中的静态成员变量能否被子类继承?

 基类定义了static静态成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子类,都只有一个static成员实例

继承与友元

 友元关系不能被继承。

猜你喜欢

转载自blog.csdn.net/m0_56910081/article/details/124551610