【C++】继承(一)--赋值转换

【本节内容】
继承的概念及定义
基类和派生类对象赋值转换

1. 继承
1.1概念

继承机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能,这样产生的类叫做派生类(子类),原有类叫做基类(父类)。

即下文所有对象关系 基类——派生类,父类——子类

继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。之前我们解除的都是函数复用,而继承属于类设计层次的复用

class Person
{
public:
	void Print()
	{
		cout << "_name" << “  ”;
		cout << "_age" << endl;
	}
protected:
	string _name = "ly";
	int _age = 21;
};
class Student :public Person    
{
protected:
	int _id;
};
class Teacher :public Person
{
protected:
	int _tid;
};
int main()
{
	Student s;
	Teacher t;
	s.Print();
	t.Print();
	system("pause");
	return 0;
}

在这里插入图片描述
s.Print(); t.Print();结果打印出两遍 _name _age可知,子类复用了父类的成员。
即在子类继承父类后,父类的成员(成员函数+成员变量)都会变成子类的一部分。

1.2 定义

1.由上面代码可知,继承的定义格式是:
在这里插入图片描述
2.继承方式和访问限定符
在这里插入图片描述
3.继承基类成员访问方式的变化

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

总结:
1)父类的私有成员无论以什么方式继承到子类中,都是不可见的。
这里的不可见指的是父类私有成员仍然继承到了派生类中,只是语法上限定派生类对象无法访问这些成员。
2)父类的public成员和protect成员在子类中的访问方式==Min(成员在父类的访问限定符,继承方式),其中public>protected>private
3)如果父类的成员不想被类外直接访问,但需要在派生类中访问,可以将父类的成员定义为protected。这里可以看出protected 成员限定符是因继承才出现的
4)使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public。虽然有默认的继承方式,但是我们最好显示写出继承方式。
5)在实际运用中,一般都使用public继承,很少用protected和private继承,因为后两者继承下来的成员只能在派生类里面使用,实际中的扩展维护性不强。

实例演示三种继承方式下基类成员访问关系的变化:

class Person
{
public:
	void Print()  { cout << _name << endl;	}	
protected:
	string _name = "ly"; 	int _age = 21;
private:
	string _sex ="女";
};
class Student :public Person     //public 继承下
{
public:
	void Display()
	{
		Print();       //可以访问基类的public 成员函数
		cout << _age << endl;    //可以访问基类的protect 成员变量
		//cout << _sex << endl; //不可访问基类的private成员变量!所以编译不通过!
		cout << _id << endl;     //可以访问派生类的protected 成员
	}
protected:
	int _id= 160;
};
2.基类和派生类对象赋值转换

1)派生类对象可以赋值给基类的对象/基类的指针/基类的引用。 这里的过程叫做切片或切割,寓意把派生类继承的基类部分切除赋值给基类。
2) 基类对象无法赋值给派生类对象。(基类中成员不够,导致非法访问)
3) 基类的指针可以通过强制类型转换赋值给派生类的指针。但是必须基类指针指向派生类对象时才是安全的,否则可能存在越界访问的问题。
在这里插入图片描述
实例演示:

class Person
{
protected:
	string _name;    //姓名
	int  _age;      //年龄
	string _sex;    //性别
};
class Student :public Person
{
public:
	int _id;     //学号
};
void Test()
{
	Student s;
	//1)子类对象可以赋值给父类(切片)
	Person p = s;      //对象
	Person *pp = &s;   //指针
	Person &rp = s;   //引用

	//2)基类对象不能赋值给派生类对象
	//s = p;      //编译不通过

	//3)基类指针可以通过强制类型转换赋值给派生类指针
	pp = &s;       //父类指针pp原本指向子类
	//pp->_id = 10;    //此时pp无法访问子类的成员
	Student *ps1 = (Student*)pp;   //将父类指针强转为子类指针
	ps1->_id = 10;       //pp可以访问子类成员
	
	pp = &p;       //父类指针pp原本指向父类
	Student *ps2 = (Student*)pp;   //也可以转换成功,但会存在越界访问的问题
	ps2->_id = 10;
}

注意:第三点中,将指向子类的父类指针pp强转为子类的结果是,指针pp由只能访问子类中父类的成员变为可访问子类中的所有成员的指针。

想对继承有更深理解的伙伴可以继续关注博主的以下几篇博客
继承(二):https://blog.youkuaiyun.com/ly_6699/article/details/88805464
讲到继承中的作用域和派生类的默认成员函数

继承(三):https://blog.youkuaiyun.com/ly_6699/article/details/88858186
讲到继承和友元,继承和静态成员,继承和组合

继承(四):https://blog.youkuaiyun.com/ly_6699/article/details/88858618
讲到复杂的菱形继承和菱形的虚拟继承

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值