day10
2023年3月14日
知识点1.继承和派生
父类 (基类)派生出子类(派生类),子类继承于父类;
子类中的成员一部分是从父类中继承过来的,一部分是自己增加的成员,从父类继承过来的表现其共性,而新增的成员体现了其个性;
1、派生类定义格式:
class 派生类名 : 继承方式 基类名{
//派生类新增的数据成员和成员函数
};
继承方式:public,公有继承;private,私有继承;protected,保护继承;
2、按父类个数分类:
单继承:指每个派生类只直接继承了一个基类的特征,即一个父类派生出一个子类;
多继承:指多个基类派生出一个派生类的继承关系,多继承的派生类直接继承了不止一个基类的特征,即多个父类派生出一个子类。
3、派生类的访问控制
派生类继承于基类,派生类拥有基类中的全部成员变量和成员方法(不包括构造和析构方法),但是在派生类中,继承的成员并不一定可以直接访问,不同的继承方式会导致不同的访问权限。
派生类访问权限规则如下:
![](https://i-blog.csdnimg.cn/blog_migrate/b1708f8cc1e737a9b1d6173f70e32ce3.png)
class Base{
public:
int a;
private:
int b;
protected:
int c;
};
//公有继承
class Son1 : public Base{
public:
//父类中的public数据在子类中public
//父类中的private数据在子类中不可见
//父类中的protected数据在子类中protected
//子类内部
void showData(){
a = 10;//子类内部可以访问
//b = 20;//子类内部不可以访问
c = 30;//子类内部可以访问
}
};
//公有继承测试
void test01()
{
Son1 son;
son.a = 10;//子类外部可以访问
//son.b = 20;//子类外部不可以访问
//son.c = 30;//子类外部不可以访问
}
//私有继承
class Son2 : private Base{
public:
//父类中的public数据在子类中private
//父类中的private数据在子类中不可见
//父类中的protected数据在子类中private
//子类内部
void showData(){
a = 10;//子类内部可以访问
//b = 20;//子类内部不可以访问
c = 30;//子类内部可以访问
}
};
//私有继承测试
void test02()
{
Son2 son;
//son.a = 10;//子类外部不可以访问
//son.b = 20;//子类外部不可以访问
//son.c = 30;//子类外部不可以访问
}
//保护继承
class Son3 : protected Base{
public:
//父类中的public数据在子类中protected
//父类中的private数据在子类中不可见
//父类中的protected数据在子类中protected
//子类内部
void showData(){
a = 10;//子类内部可以访问
//b = 20;//子类内部不可以访问
c = 30;//子类内部可以访问
}
};
//保护继承测试
void test03()
{
Son3 son;
//son.a = 10;//子类外部不可以访问
//son.b = 20;//子类外部不可以访问
//son.c = 30;//子类外部不可以访问
}
知识点2.继承中的构造和析构
1、在子类实例化对象时,会默认先调用父类的无参构函数,然后再调用自己的构造函数,最后调用析构函数时,先调用自己的析构函数,再调用父类的析构函数;
2、若子类中含有其他类的对象成员,则在子类实例化对象时,调用构造和析构的顺序是:父类的无参构造 -> 对象成员类的构造函数 -> 子类的构造函数 -> 子类的析构函数 -> 对象成员类的析构函数 -> 父类的析构函数;
3、若子类想调用父类的有参构造函数,则必须使用初始化列表来调用父类的有参构造函数,且在父类具有自定义有参构造函数时,必须自定义无参构造函数,不然子类在实例化对象时,调用默认无参构造函数被屏蔽,程序报错。
4、案例:
#include <iostream>
using namespace std;
class Other{
public:
Other(){
cout << "Other的无参构造" << endl;
}
~Other(){
cout << "Other的析构函数" << endl;
}
};
class Base{
private:
int a;
public:
Base(){
cout << "父类的无参构造" << endl;
}
Base(int a){
this->a = a;
cout << "父类的有参构造" << endl;
}
~Base(){
cout << "父类的析构函数" << endl;
}
};
class Son : public Base{
private:
int b;
public:
Son(){
cout << "子类的无参构造" << endl;
}
Son(int b) : b(b){
cout << "子类的有参构造int" << endl;
}
//采用初始化列表调用父类中的有参构造,并传递a的值
Son(int a, int b) : Base(a){
//this->a = a;//err,父类中私有成员不可直接访问
this->b = b;
cout << "子类的有参构造int int" << endl;
}
~Son(){
cout << "子类的析构函数" << endl;
}
//Other other;
};
void test01()
{
//子类调用无参构造初始化实例对象
Son son1;
}
void test02()
{
//子类调用一个参数的有参构造实例化对象
Son son2(10);
}
void test03()
{
//子类中含有其他类的对象成员,调用无参构造实例化对象
Son son3;
}
void test04()
{
//子类调用两个参数的有参构造实例化对象
//必须采用初始化列表才会调用父类的有参构造
Son son4(10, 20);
}
int main()
{
test04();
return 0;
}
test01的运行结果:
![](https://i-blog.csdnimg.cn/blog_migrate/ed2456e210574c0acb2a1a8e4fe8963d.png)
test02的运行结果:
![](https://i-blog.csdnimg.cn/blog_migrate/f8ce12edd69517f154096340c4af4425.png)
test03的运行结果:
![](https://i-blog.csdnimg.cn/blog_migrate/8efe010eef3ae6d3507298666fa9b0b9.png)
test04的运行结果:
![](https://i-blog.csdnimg.cn/blog_migrate/e412be5647b2a953a5fe263a69b31d48.png)