C++ 继承★★★★★

Hello!!大家早上中午晚上好!!今天来复习C++继承部分知识点,这章概念比较多,理解为上!!

一、继承的概念

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

二、语法定义格式

2.1继承方式
public继承
class Person //基类
{
public:
	char _name[10]="张三";//姓名
	char _tell[11]="1122334455";//电话
protected:
	char _sex[5] = "男";//性别
private:
	char _adress[10]="中国";//地址
};
class Student:public Person //公有继承Person的派生类 Student
{
public:
	int _stuid=1234;//学号
	char _major[10]="数学";//专业
	void print()
	{
        cout<<_name<<endl;
        cout<<_tell<<endl;
		cout << _sex<<endl;
		//cout << _adress << endl;
	}
};
int main()
{
	Student s1;
	cout << s1._name << " - " << s1._tell << " - " << s1._stuid << " - " << s1._major << endl;
	s1.print();
	return 0;
}

运行:

public继承的派生类类外只能访问基类的public成员:

类内可以访问基类的public、protected成员,不能访问基类的private成员:

2.2protected继承

代码更改:

class Student:protected Person //保护继承Person的派生类 Student
{
public:
	int _stuid=1234;//学号
	char _major[10]="数学";//专业
	void print()
	{
        cout<<_name<<endl;
        cout<<_tell<<endl;
		cout << _sex<<endl;
		//cout << _adress << endl;
	}
};

protected继承的派生类在类外不可访问任何基类成员:

在类内除了基类的private成员,其他成员皆可访问:

2.3private继承

代码更改:

class Student:private Person //私有继承Person的派生类 Student
{
public:
	int _stuid=1234;//学号
	char _major[10]="数学";//专业
	void print()
	{
        cout<<_name<<endl;
        cout<<_tell<<endl;
		cout << _sex<<endl;
		//cout << _adress << endl;
	}
};

private继承的派生类在类外不能访问任何基类成员:

在类内除了基类的private成员不可访问,其他成员皆可访问:

 

三、总结不同继承方式基类成员在派生类中的访问方式发生的变化

注:

①不可见表示语法上限制访问(类外类内皆不可访问),跟private不一样,private在类外不能访问在类内可以访问;(基类private成员不管以何种方式继承在派生类中都不可见!!!)

②如果基类成员不想在类外被访问,但需要在派生类内可以访问,就定义为protected继承;

③如果不写继承方式,class默认private继承,struct默认public继承;

④实际运用一般使用的都是public继承,几乎很少使用protected、private继承;

⑤可以看出基类的成员在派生类中的访问方式都是转成权限较小的那个;

四、基类和派生类的赋值兼容

4.1概念

派生类对象可以赋值给基类的对象、指针、引用;这种赋值方式叫做赋值兼容或者叫做赋值转换、切割、切片;

图解:

反之:

基类对象不能赋值给派生类对象!!

基类的指针和引用可以通过强制类型转化的方式赋值给派生类的指针和引用,但是基类的指针必须指向派生类对象的时候才是安全的!!!

int main()
{
	Person p1;
	Person* p2 = &p1;
	Student s1;
	//1.子类对象可以赋值个父类对象;
	p1 = s1;
	//子类对象的地址可以赋值父类指针;
	Person* ptr1 = &s1;
	//子类对象可以赋值给父类引用
	Person& pp1 = s1;

	//2.基类对象不能赋值给子类对象
	//s1 = p1; 报错
	
	//3.基类的指针可以赋值类子类指针,但必须基类的指针指向子类,否则会越界访问
	Student* sptr1 = (Student*)ptr1;
	sptr1->_stuid = 10;

	Student* sptr2 = (Student*)p2;//存在越界访问
	sptr2->_stuid = 10;

	return 0;
}

五、基类和派生类的作用域

5.1在继承体系中,基类和派生类都有自己独立的作用域

当基类和派生类中出现同名成员时,派生类自动屏蔽基类的同名成员,这两个同名成员之间构成隐藏关系或者叫做重定义!

class A //父类
{
public:
//父类成员
	void print()  
	{
		cout << "我被隐藏了!!" << endl;
	}
	int getAName()
	{
		return _name;
	}
	int _name = 158;
};

class B :public A   //子类
{
public :
//子类成员
	void print()
	{
		cout << "我没隐藏!!" << endl;
	}
	int getBName()
	{
		return _name;
	}
private:
	int _name = 178;
};

int main()
{
	A a;
	B b;
	a.print();//调用A类的print
	cout<<a.getAName()<<endl;
	b.print();//调用B类的print
	cout << b.getBName() << endl;//同名name构成隐藏屏蔽父类的name
	return 0;
}

运行:

以上继承关系中:

A类的print和B类的print同名构成隐藏关系,B类对象调用时自动屏蔽A类中的print;

A类的_name和B类的_name同名构成隐藏关系,B类对象调用时自动屏蔽A类中的_name;

六、继承体系中派生类的默认成员函数

我们不写派生类会自动生成:

6.1派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认构造函数,则必须在派生类的构造函数的初始化列表中显示调用;
6.2派生类的拷贝构造函数必须调用基类的拷贝构造函数完成基类的拷贝初始化;
6.3派生类的operator=必须调用基类的operator=完成基类的复制;
6.4派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员,因为这样才能保证派生类对象先清理派生类的成员再清理基类的成员的顺序;
6.5派生类初始化先调用基类构造在调用派生类构造;
6.6派生类清理先调用派生类析构再调用基类析构;
6.7因为在某些场景析构函数需要构成重写,重写的条件之一是函数名相同,所以编译器会对析构函数名进行特殊处理,处理成destrutor(),所以父类析构函数不加virtual的情况下,子类析构函数与父类析构函数构成隐藏关系;

今天就复习到这里!!如果您有收获请点赞收藏+关注哦!!谢谢!!!

如果您有更好的建议欢迎评论区留言!!

咱下期见!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值