C++初阶继承

Posted Huang_ZhenSheng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++初阶继承相关的知识,希望对你有一定的参考价值。

目录

继承的概念和定义

继承中的作用域

派生类的默认成员函数

构造函数:

析构函数:

赋值&析构函数

复杂的菱形继承及菱形虚拟继承

继承的总结和反思


继承的概念和定义

class Person

public:
	void Print()
	
		cout << "name:" << _name << endl;
		cout << "age:" << _age << endl;
	
protected:
	string _name = "peter";
	int _age = 18;
;
//Student继承了Person,Student中就拥有了Person的成员
//person 叫父类/基类
//student叫子类/派生类
class Student :public Person

protected:
	int _stuid;
;
class Teacher :public Person

protected:
	int _Jobid;
;
int main()

	Student s;
	Teacher t;
	s.Print();
	t.Print();
	return 0;

继承中的作用域

B中的fun和A中的fun不是构成重载,因为不是在同一个作用域

B中的fun和A中的fun构成隐藏,成员函数满足函数名相同就构成隐藏

//A和B类的两个fun构成隐藏关系,继承中函数名相同就是隐藏
class  A

public:
	void fun()
	
		cout << "func()" << endl;
	
;
class B :public A

public:
	void fun(int i)
	
;
void Test()

	B b;
	b.fun(10);
	b.fun();
	//想调用父类的=>b.A::fun()

int main()

	Test();
	return 0;

派生类的默认成员函数

构造函数:

要注意的是父类成员是作为一个整体,调用父类的构造函数进行初始化

class Person

public:
	//Person(const char* name = "peter")
	Person(const char* name )
		: _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:
	//子类构造函数——我们不写,编译器默认生成
	//1.继承的父类成员---作为一个整体调用父类的构造函数初始化
	//2.自己的内置类型成员---不处理(除非给了缺省值)
	//3.自己的自定义类型成员---调用它的默认构造函数

	//我们要自己实现子类构造函数
	Student(const char*name, int id, const char* address)
	//要注意的是父类成员是作为一个整体,调用父类的构造函数进行初始化
	:Person(name)
	, _id(id)
	, _address(address)
	
private:
	int _id;//内置类型
	string _address;//自定义类型
;
int main()

	Student s("黄振盛",1,"厦门市");
	return 0;

析构函数:

class Person

public:
	Person(const char* name = "peter")
	//Person(const char* name )
		: _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:
	//子类拷贝构造函数——我们不写,编译器默认生成
	//1.继承的父类成员作为一个整体---调用父类的拷贝构造
	//2.自己的内置类型成员---调用它的拷贝构造
	//3.自己的自定义类型成员---值拷贝
	Student(const char*name, int id, const char* address)
		//要注意的是父类成员是作为一个整体,调用父类的构造函数进行初始化
		:Person(name)
		, _id(id)
		, _address(address)
	
	//自己实现拷贝构造
	Student(const Student& s)
		:Person(s)
		,_id(s._id)
		, _address(s._address)
	
private:
	int _id;//内置类型
	string _address;//自定义类型
;
int main()

	Student s1("小红",100,"厦门市");
	Student s2(s1);
	return 0;

赋值&析构函数

class Person

public:
	//Person(const char* name = "peter")
	Person(const char* name )
		: _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:
	//子类拷贝构造函数——我们不写,编译器默认生成
	//1.继承的父类成员作为一个整体---调用父类的拷贝构造
	//2.自己的内置类型成员---调用它的拷贝构造
	//3.自己的自定义类型成员---值拷贝
	Student(const char*name, int id, const char* address)
		//要注意的是父类成员是作为一个整体,调用父类的构造函数进行初始化
		:Person(name)
		, _id(id)
		, _address(address)
	
	自己实现拷贝构造
	//Student(const Student& s)
	//	:Person(s)
	//	,_id(s._id)
	//	, _address(s._address)
	//
	//赋值:
	Student& operator = (const Student& s)
	
		if (this != &s)
		
			_id = s._id;
			_address = s._address;
			Person::operator = (s);
		
		return *this;
	
	//析构
	//子类拷贝构造函数——我们不写,编译器默认生成
	//1.继承的父类成员作为一个整体---调用父类的析构函数
	//2.自己的内置类型成员---不处理
	//3.自己的自定义类型成员---调用它的析构函数
	//自己实现
	//子类析构函数和父类析构函数构成隐藏关系--why?
	//因为编译器会对析构函数名做特殊处理,所有类的析构函数都会被统一处理成destructor()
	//为什么编译器会做这个处理呢?——析构函数要构成多态重写
	~Student()
	
		Person::~Person();//子类的析构函数在执行结束后会自动调用父类的析构函数
	
private:
	int _id;//内置类型
	string _address;//自定义类型
;
int main()

	Student s1("小红",100,"厦门市");
	Student s2(s1);
	Student s3("小蓝",200,"泉州市");
	s1 = s3;
	return 0;

复杂的菱形继承及菱形虚拟继承

先来看一段代码:

class B : public A

public:
	int _b;
;
// class C : public A
class C : public A

public:
	int _c;
;
class D : public B, public C

public:
	int _d;
;
int main()

	D d;
	d.B::_a = 1;
	d.C::_a = 2;
	d._b = 3;
	d._c = 4;
	d._d = 5;
	//d._a = 0;
	return 0;

 再看一段虚继承代码:

class A

public:
	int _a;
;
// class B : public A
class B : virtual public A

public:
	int _b;
;
// class C : public A
class C : virtual public A

public:
	int _c;
;
class D : public B, public C

public:
	int _d;
;
int main()

	D d;
	d.B::_a = 1;
	d.C::_a = 2;
	d._b = 3;
	d._c = 4;
	d._d = 5;
	d._a = 0;
	return 0;

 将上面两段内存代码对比如下:

存了个偏移量 

 

访问继承的虚基类对象成员,都是取偏移量计算

小结:

多继承带来的问题是菱形继承,菱形继承解决引来了虚拟继承,虚拟继承在腰部的位置!

如何解决:偏移量!

继承的总结和反思

1.最好不要设计出菱形继承

2.public继承是一种 is-a 的关系,组合是一种 has-a 的关系,尽量使用耦合度低(模块(类..)间关联度越低,独立性越高,耦合度越低)的组合

以上是关于C++初阶继承的主要内容,如果未能解决你的问题,请参考以下文章

对象初阶_继承

laravel 视图怎么继承公共头部尾部

继承初阶笔记

JavaScript初阶-------- 继承发展史命名空间

C++初阶:模板初阶函数模板 | 类模板

C++初阶:模板初阶函数模板 | 类模板