从这篇文章开始,我们正式进入c++进阶篇章
继承的概念及定义
概念
继承(inheritance)机制是⾯向对象程序设计使代码可以复⽤的最重要的⼿段,它允许我们在保持原有 类特性的基础上进⾏扩展
通俗来讲就是:父亲的遗产传给自己的子女,由子女去使用
增加⽅法(成员函数)和属性(成员变量),这样产⽣新的类,称派⽣类。
这个所谓的派生类就是上面提到过的子女
继承定义
定义格式
class 派生类(子类):public 基类(父类)
这里的public是继承方式
{
语句;
}
继承基类(父类)成员访问方式的变化
1.基类的私有成员在派生类中无法访问。
2.基类private的成员不能在派生类中不能被直接访问,需要在派生类中定义为protected才能被访问。
3.使⽤关键字class时默认的继承⽅式是private,使⽤struct时默认的继承⽅式是public,不过最好显 ⽰的写出继承⽅式。
4.在实际运⽤中⼀般使⽤都是public继承,⼏乎很少使⽤protetced/private继承,也不提倡使⽤ protetced/private继承,因为protetced/private继承下来的成员都只能在派⽣类的类⾥⾯使⽤,实 际中扩展维护性不强。
继承中的作用域
隐藏规则
1. 在继承体系中基类和派⽣类都有独⽴的作⽤域。
2. 派⽣类和基类中有同名成员,派⽣类成员将屏蔽基类对同名成员的直接访问,这种情况叫隐藏。
3. 需要注意的是如果是成员函数的隐藏,只需要函数名相同就构成隐藏。
当然啦,在实际中在继承体系⾥⾯最好不要定义同名的成员。
派生类的默认成员
4个常⻅默认成员函数
默认的成员函数就是指不需要我们去编写的函数,编译器会自动生成的成员函数
1. 派⽣类的构造函数必须调⽤基类的构造函数初始化基类的那⼀部分成员。如果基类没有默认的构造 函数,则必须在派⽣类构造函数的初始化列表阶段显⽰调⽤。
2. 派⽣类的拷⻉构造函数必须调⽤基类的拷⻉构造完成基类的拷⻉初始化。
3.派⽣类的operator=必须要调⽤基类的operator=完成基类的复制。但需要注意的是派生类的operator= 隐藏了基类的operator=,因此要显式调用基类的operator= 时,需要指定基类作用域
4. 派⽣类的析构函数会在被调⽤完成后⾃动调⽤基类的析构函数清理基类成员。
实现一个不能被继承的类
⽅法1:基类的构造函数私有,派⽣类的构成必须调⽤基类的构造函数,但是基类的构成函数私有化以 后,派⽣类看不⻅就不能调⽤了,那么派⽣类就⽆法实例化出对象。
方法2: :C++11新增了⼀个final关键字,final修改基类,派⽣类就不能继承了。
继承与友元
友元关系不能继承,也就是说基类友元不能访问派⽣类私有和保护成员 。
由此可见有缘关系不能继承
继承与静态成员
基类定义了static静态成员,则整个继承体系⾥⾯只有⼀个这样的成员。⽆论派⽣出多少个派⽣类,都 只有⼀个static成员实例。
class Person
{
public:
string _name;
static int _count;
};
int Person::_count = 0;
class Student : public Person
{
protected:
int _stuNum;
};
int main()
{
Person p;
Student s;
// 这⾥的运⾏结果可以看到⾮静态成员 _name 的地址是不⼀样的
// 说明派⽣类继承下来了,⽗派⽣类对象各有⼀份
cout << &p._name << endl;
cout << &s._name << endl;
// 这⾥的运⾏结果可以看到静态成员 _count 的地址是⼀样的
// 说明派⽣类和基类共⽤同⼀份静态成员
cout << &p._count << endl;
cout << &s._count << endl;
// 这⾥的运⾏结果可以看到⾮静态成员 _name 的地址是不⼀样的
// 说明派⽣类继承下来了,⽗派⽣类对象各有⼀份
cout << &p._name << endl;
cout << &s._name << endl;
// 这⾥的运⾏结果可以看到静态成员 _count 的地址是⼀样的
// 说明派⽣类和基类共⽤同⼀份静态成员
cout << &p._count << endl;
cout << &s._count << endl;
return 0;
}
多继承及其菱形继承问题
继承模型
单继承
单继承:⼀个派⽣类只有⼀个直接基类时称这个继承关系为单继承
举个例子
这个就是单继承
多继承
多继承:⼀个派⽣类有两个或以上直接基类时称这个继承关系为多继承
值得一提的是多继承对象在内存中的模型, 它的模型是先继承的基类在前⾯,后⾯继承的基类在后⾯,派⽣类成员在放到最后⾯
那么接下来讲一下一种特殊的继承模型
菱形继承
菱形继承是多继承的⼀种特殊情况。
菱形继承的问题,从下⾯的对象成员模型构造,可以 看出菱形继承有数据冗余和⼆义性的问题,在Assistant的对象中Person成员会有两份。⽀持多继承就 ⼀定会有菱形继承,像Java就直接不⽀持多继承,规避掉了这⾥的问题,所以实践中我们也是不建议 设计出菱形继承这样的模型的。
虚继承
class Person
{
public:
string _name; // 姓名
/*int _tel;
int _age;
string _gender;
string _address;
*/
// ...
}; // 使⽤虚继承 Person 类
class Student : virtual public Person
{
protected:
int _num; // 学号
}; // 使⽤虚继承 Person 类
class Teacher : virtual public Person
{
protected:
int _id; // 职⼯编号
};
// 教授助理
class Assistant : public Student, public Teacher
{
protected:
string _majorCourse; // 主修课程
};
int main()
{
// 使⽤虚继承,可以解决数据冗余和⼆义性
Assistant a;
a._name = "peter";
return 0;
}
继承和组合
public继承是一种is-a的关系,即每个派生类对象都素一个基类对象
组合是一种has-a的关系,假设b组合了a,每个b对象中都有一个a对象
都看到这里了,各位观众老爷给个三联呗,谢谢啦!!!