[C++]继承(续)

一、基类和派生类对象赋值转换

在public继承时,父类和子类是一个"is - a"的关系。

子类对象赋值给父类对象/父类指针/父类引用,我们认为是天然的,中间不产生临时对象,也叫作父子类赋值兼容规则(切割/切片)。

cpp 复制代码
#include<iostream>
#include<string>


using namespace std;

class person
{
public:
	void print()
	{
		cout << "name: " << _name << endl;
		cout << "id: " << _id << endl;
		cout << "age: " << _age << endl;
	}

protected:
	string _name = "zhangsan";
	string _id = "111111";
	int _age = 18;
};

// 继承后父类的person的成员(成员函数+成员变量)都会变成子类的一部分。
// 这里体现出了student和teacher复用了Person的成员。
class student :public person
{


private:
	string _class;
	
};

class teacher :public person
{


private:
	string _collage;
};



int main()
{
	student s;
	teacher t;


	float a = 1.1;

//这里的赋值会产生临时变量,隐式类型转换
	int b = a;

//这里必须加const,因为c指向的是所产生的临时变量,它是一个常量
	const int& c = a;

	person p = s;

//这里就不用加const
	person& rp = t;

	return 0;
}

二、继承中的作用域

父类和子类可以拥有同名成员,因为他们是独立作用域。默认情况直接访问是子类的,子类同名成员隐藏父类同名成员。此时,如果我们想要访问父类的同名成员,需指定类域。

在继承中,对于同名的成员函数,函数名相同则构成隐藏,不管参数和返回值。

cpp 复制代码
#include<iostream>
#include<string>


using namespace std;

class person
{
public:
	void print()
	{
		cout << "name: " << _name << endl;
		cout << "id: " << _id << endl;
		cout << "age: " << _age << endl;
	}

protected:
	string _name = "zhangsan";
	string _id = "111111";//身份证号
	int _age = 18;
};

// 继承后父类的person的成员(成员函数+成员变量)都会变成子类的一部分。
// 这里体现出了student和teacher复用了Person的成员。
class student :public person
{
public:
	void print()
	{
		cout << "name: " << _name << endl;
		cout << "身份证号: " << person::_id << endl;
		cout << "学号: " << _id << endl;
		cout << "age: " << _age << endl;
	}

private:
	string _class;
	string _id = "222222";//学号
};

class teacher :public person
{


private:
	string _collage;
};



int main()
{
	student s;

	s.print();

	return 0;
}

三、派生类的默认成员函数

6个默认成员函数,"默认"的意思是指我们不写,编译器会变我们自动生成一个,那么在派生类中,这几个成员函数是如何生成的呢?

  1. 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认的构造函数,则必须在派生类构造函数的初始化列表阶段显式调用。
  2. 派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。
  3. 派生类的operator=必须要调用基类的operator=完成基类的复制。
  4. 派生类的析构函数会在被调用完成后自动调用基类的析构函数清理基类成员。因为这样才能保证派生类对象先清理派生类成员再清理基类成员的顺序。(保证析构安全)
  5. 派生类对象初始化先调用基类构造再调派生类构造。
  6. 派生类对象析构清理先调用派生类析构再调基类的析构。
cpp 复制代码
class Person
{
public:
	Person(const char* name = "aaa")
		: _name(name)
	{
		cout << "Person()" << endl;
	}
	Person(const Person& p)
		: _name(p._name)
	{
		cout << "Person(const Person& p)" << endl;
	}
	Person& operator=(const Person& p)
	{
		cout << "Person operator=(const Person& p)" << endl;
		if (this != &p)
			_name = p._name;
		return *this;
	}
	~Person()
	{
		cout << "~Person()" << endl;
	}
protected:
	string _name; // 姓名
};
class Student : public Person
{
public:
	Student(const char* name, int num)
		: Person(name)
		, _num(num)
	{
		cout << "Student()" << endl;
	}
	Student(const Student& s)
		: Person(s)
		, _num(s._num)
	{
		cout << "Student(const Student& s)" << endl;
	}
	Student& operator = (const Student& s)
	{
		cout << "Student& operator= (const Student& s)" << endl;
		if (this != &s)
		{
			Person::operator =(s);
			_num = s._num;
		}
		return *this;
	}
	~Student()
	{
		cout << "~Student()" << endl;
	}
protected:
	int _num; //学号
};
void Test()
{
	Student s1("zhangsan", 20);
	Student s2(s1);
	Student s3("lisi", 23);
	s1 = s3;
}


int main()
{
	Test();


	return 0;
}

四、补充

  1. 友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员。
  2. 基类定义了static静态成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子类,都只有一个static成员实例 。
相关推荐
科学实验家5 分钟前
最小生成树:Prim,kruskal
数据结构·c++·算法
学习智者8 分钟前
《玄》IDE v3.6.3重磅发布:全功能修复与性能飞跃
开发语言·c++·ide·算法·中文语言 玄
Jasmine_llq10 分钟前
《P10263 [GESP202403 八级] 公倍数问题》
算法·数论·快速 io 优化·埃氏筛(倍数枚举)·线性遍历求和
2402_8828938612 分钟前
C++异常:从概念到实践的一篇博客
c++·异常
橘子汽水16812 分钟前
Leetcode 322 279 零钱兑换,完全平方数
算法·leetcode
奔跑吧树袋熊14 分钟前
多租户隔离该做到哪一层:从连接池到 ORM 的取舍
开发语言·数据库·oracle·系统架构
大江东去浪淘尽千古风流人物17 分钟前
【LoMa】局部特征匹配重访:从LoMa-B到旋转不变LoMa-R的架构与工程实践
开发语言·深度学习·计算机视觉·r语言·视觉定位·sfm·局部特征匹配
菜鸟~noob23317 分钟前
【电子战】测向精度极限——克拉美-罗下限(CRLB)与误差分析【含matlab代码】
开发语言·matlab
kevin_kang18 分钟前
第01章 VoiceAgent 的总体架构与完整流程
算法
m0_7345717618 分钟前
深入理解C++ 析构函数<二>析构顺序
开发语言·c++