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

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;
}

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

1.2 定义

1.由上面代码可知,继承的定义格式是:
【C++】继承(一)
2.继承方式和访问限定符
【C++】继承(一)
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) 基类的指针可以通过强制类型转换赋值给派生类的指针。但是必须基类指针指向派生类对象时才是安全的,否则可能存在越界访问的问题。
【C++】继承(一)
实例演示:

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.csdn.net/ly_6699/article/details/88805464
讲到继承中的作用域和派生类的默认成员函数

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

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

相关文章:

  • 2021-09-25
  • 2022-12-23
  • 2021-07-07
  • 2021-10-23
  • 2021-06-30
  • 2021-06-18
猜你喜欢
  • 2021-08-26
  • 2022-12-23
  • 2021-09-22
  • 2021-04-12
  • 2021-06-16
  • 2021-07-05
  • 2021-08-27
相关资源
相似解决方案