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++进阶继承的主要内容,如果未能解决你的问题,请参考以下文章
C++进阶第十五篇—C++中的继承(继承的概念+菱形继承+虚拟继承+组合)
C++进阶:继承C++为什么要引入继承 | 继承概念及定义 | 基类和派生类对象赋值转换 | 继承中的作用域 | 派生类的默认成员函数 | 继承与友元/静态成员 | 复杂的菱形继承及菱形虚拟继承
C++进阶:继承C++为什么要引入继承 | 继承概念及定义 | 基类和派生类对象赋值转换 | 继承中的作用域 | 派生类的默认成员函数 | 继承与友元/静态成员 | 复杂的菱形继承及菱形虚拟继承