[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成员实例 。
相关推荐
大千AI助手2 分钟前
RLHF:人类反馈强化学习 | 对齐AI与人类价值观的核心引擎
人工智能·深度学习·算法·机器学习·强化学习·rlhf·人类反馈强化学习
wkj0014 分钟前
php中调用对象的方法可以使用array($object, ‘methodName‘)?
android·开发语言·php
hudawei99632 分钟前
kotlin中withContext,async,launch几种异步的区别
android·开发语言·kotlin
消失的旧时光-194336 分钟前
Kotlin 常用语法糖完整整理
android·开发语言·kotlin
每次的天空40 分钟前
Android-重学kotlin(协程源码第一阶段)新学习总结
开发语言·学习·kotlin
Dovis(誓平步青云)43 分钟前
探索飞算 JavaAI 进阶:解锁高效Java开发的新维度
java·开发语言·飞算java
CS semi43 分钟前
C++每日刷题day2025.7.10
开发语言·c++
还听珊瑚海吗1 小时前
Python(一)
开发语言·python
满分观察网友z1 小时前
从UI噩梦到导航之梦:一道LeetCode经典题如何拯救了我的项目(116. 填充每个节点的下一个右侧节点指针)
算法
DoraBigHead2 小时前
小哆啦解题记——两数失踪事件
前端·算法·面试