c++继承特点,菱形继承,访问方式,默认成员函数

目录

继承概念

继承特性

继承后成员访问的方式的变化

子父类成员重命名

派生类的默认成员函数

​编辑

菱形继承

小tip


继承概念

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

格式

继承特性

继承后成员访问的方式的变化

tip:
1.使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过
最好显示的写出继承方式。
2. 在实际运用中一般使用都是public继承,几乎很少使用protetced/private继承,也不提倡
使用protetced/private继承,因为protetced/private继承下来的成员都只能在派生类的类里
面使用,实际中扩展维护性不强。
3. 基类private成员在派生类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在
派生类中能访问,就定义为protected。可以看出保护成员限定符是因继承才出现的。
4.根据上面这个表格其实可以发现,我们继承的时候是去取最小的访问限定。比如一个函数的权限是protected用public方式继承后访问限定任然是protected。

子父类成员重命名

子类和父类中有同名成员,子类成员将屏蔽父类对同名成员的直接访问,这种情况叫隐藏,
也叫重定义。(在子类成员函数中,可以使用 基类::基类成员 显示访问)

class peopel {
protected:
	string name="111";
};

class teacher : public peopel {

	void show()
	{
		cout <<name<<peopel::name;
	}

protected:
	string name="222";
};

如果我们不指定就是子类里面的name

派生类的默认成员函数

1.对于构造函数,父类不显示的写,会去调用自己的默认构造,子类回去调用自己的默认构造,注意这个过程是先完成父类的构造,再完成子类的构造。

如:

class Person {
public:
	Person(const string& name="牢大") :
	_name(name)
	{}
	Person(const Person& data): _name(data._name)
	{}

	virtual~Person() {
	};
protected:
	string _name;
};


class Student :public Person {
public:
	Student( const string& name="", const string& id="") : _id(id) {}
	Student(const Student&data):Person::Person(data),_id(data._id){}


	void Show()
	{
		cout << _id << _name;
	}
	virtual~Student() {};
protected:
	string _id;
};

void Test2()
{
	Student st1("zgw", "444");
	st1.Show();
}

这里我们就算是写了这个参数,也只会去执行无参的默认构造。

只有当我们去显示的写了传参才有用。

2.拷贝构造同上。

3.析构函数,派生类对象析构清理先调用派生类析构再调基类的析构。因为后续一些场景析构函数需要构成重写,重写的条件之一是函数名相同(这个我后面会讲解)。那么编译器会对析构函数名进行特殊处理,处理成destrutor(),所以父类析构函数加virtual的情况下,子类析构函数和父类析构函数构成隐藏关系。这里有一些多态的知识。
 

class Person {
public:
	Person(const string& name="牢大") :
	_name(name)
	{}
	Person(const Person& data): _name(data._name)
	{}

	~Person() {
		cout << "~Person()" << endl;
	};
protected:
	string _name;
};


class Student :public Person {
public:
	Student( const string& name="", const string& id="") :Person::Person(name), _id(id) {}
	Student(const Student&data):Person::Person(data),_id(data._id){}


	void Show()
	{
		cout << _id << _name;
	}
	~Student() { 
		cout << "~Student()" << endl;
	};
protected:
	string _id;
};

void Test2()
{
	Student st1("zgw", "444");
	st1.Show();
}

菱形继承

当我们写出这样的代码:

这样的继承,Assistant里面就有两份Person的数据,这样就出现了数据冗余和二义性,现实世界其实有这种场景如一个导员既是学生又是老师,但是写代码不建议这么写,所以出现这种情况我们一般用虚继承

如:

class person
{
public:
	string _name; // 姓名
};
class student : virtual public person
{
protected:
	int _num; //学号
};
class Teacher : virtual public person
{
protected:
	int _id; // 职工编号
};
class Assistant : public student, public Teacher
{
protected:
	string _majorCourse; // 主修课程
};

void Test3()
{
	Assistant a;
	a._name = "peter";
	cout << a._name;
}

这样就不会出现二义性。

小tip

1.基类定义了static静态成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子
类,都只有一个static成员实例 。

2.友元函数不能被继承。

最近更新

  1. 交换机(Switches)和桥(Bridges)的区别

    2024-07-09 17:32:08       0 阅读
  2. 测试面试宝典(二十一)—— get和post的区别

    2024-07-09 17:32:08       0 阅读
  3. ESP8266AT指令查看有哪些指令可用(3)

    2024-07-09 17:32:08       0 阅读

热门阅读

  1. uniapp页面进来直接横屏

    2024-07-09 17:32:08       7 阅读
  2. Django权限系统如何使用?

    2024-07-09 17:32:08       7 阅读
  3. 开源 WAF 解析:选择最适合你的防护利器

    2024-07-09 17:32:08       10 阅读
  4. VPN是什么?

    2024-07-09 17:32:08       8 阅读
  5. Android C++系列:Linux进程(一)

    2024-07-09 17:32:08       11 阅读
  6. Oracle查询固定值查询

    2024-07-09 17:32:08       9 阅读
  7. android Gradle储蓄地址

    2024-07-09 17:32:08       11 阅读
  8. 基于BERT的大规模文本处理实战

    2024-07-09 17:32:08       8 阅读
  9. 【LeetCode 0242】【Map/排序】有效的异位词

    2024-07-09 17:32:08       9 阅读