一、继承的含义
由父类(基类)派生出子类(派生类),子类会选择性地继承父类的特性。借此,我们可以减少代码的冗余 提高代码的重用性。
二、继承的语法
class 子类: 继承方式 父类名{
//子类新增的数据成员和成员函数
};
三、三种继承方式
- 继承方式为pubilc
此时子类继承了父类中的public和protected属性,其中两种属性在子类中的访问权限与在父类中相同,但是父类中的private属性子类虽然被继承,但是被隐藏无法访问。
class teacher {
public:
string name;
protected:
int age;
private:
int score;
};
class student: public teacher {
public:
void look()
{
name="Tom";
age=18;
score=;
}
};
- 继承方式为protected
此时子类继承了父类中的public和protected属性,其中两种属性在子类中的访问权限都为protected,但是父类中的private属性子类虽然被继承,但是被隐藏无法访问。
class teacher {
public:
string name;
protected:
int age;
private:
int score;
};
class student: protected teacher {
public:
void look()
{
name="Tom";
age=18;
score=100;
}
};
void test1()
{
student stu;
stu.name="TOM";
stu.age=18;
stu.score=100;
}
- 继承方式为private
此时子类继承了父类中的public和protected属性,其中两种属性在子类中的访问权限都为private,但是父类中的private属性子类虽然被继承,但是被隐藏无法访问。通过给student类一个子类,发现由于student类内的属性都是private所以子类无法访问。
class teacher {
public:
string name;
protected:
int age;
private:
int score;
};
class student: private teacher {
public:
void look()
{
name="Tom";
age=18;
score=100;
}
};
class son: public student {
public:
void look()
{
name="Tom";
age=10;
score=10;
}
};
四、构造函数和析构函数的顺序
- 创建子类对象的同时也会创建一个父类对象
- 构造函数的执行是父类先于子类,析构函数的执行是子类先于父类
#include <iostream>
#include <string>
using namespace std;
class teacher {
public:
teacher()
{
cout<<"父类的构造函数"<<endl;
}
~teacher()
{
cout<<"父类的析构函数"<<endl;
}
};
class student: private teacher {
public:
student()
{
cout<<"子类的构造函数"<<endl;
}
~student()
{
cout<<"子类的构造函数"<<endl;
}
};
void test1()
{
student stu;
}
int main()
{
test1();
system("pause");
}
- 如果调用了其他类作为成员:
五、解决子类和父类中的同名成员
- 当子类和父类中有同名的成员变量时,直接调用子类的该成员变量,访问的是子类的而不是父类的。
- 可以通过加作用域来判断访问的是否是继承于父类的属性
- 如果子类中的成员函数和父类的相同,则会隐藏父类的所有该同名函数,但是我们可以通过作用域来访问父类的成员函数
- 同名的静态函数、静态成员变量处理方式和上面相同
六、多继承
- 多继承的语法:
class 子类: 继承方式1 父类名1,继承方式2 父类名2,继承方式3 父类名3,....
{
};
- 实际开发中不支持使用多继承,因为继承多个父类容易出现同名成员的冲突,这时需要使用加上作用域的方法来解决。
七、菱形继承
- 菱形继承的概念:
当一个类继承了多个父类,而那些父类又有他们共同的父类,那么这些父类中就会有一些相同的属性。这样的话第一个类(所有类的子类)就会多次继承同一种数据,这样会造成资源的浪费,而且容易造成二义性。
- 解决方法
①对于二义性的解决方法在前面都有介绍,就是给成员属性加上作用域。但是这样还是会造成资源浪费。
②为了同时解决二义性和资源浪费的问题,我们可以采用虚继承。
八、虚继承
- 虚继承的语法
class 子类:virtual public 父类
{
};
- 虚继承的本质
利用虚基类指针vbptr指向虚基类表,而虚基类表vbtable保存了当前的虚指针相对于虚基类的首地址的偏移量。通过偏移量找到父类中的属性,这样就可以只用一份数据的资源了。
- 虚继承在实际开发中也不支持使用。