目录
概念
继承类似于函数的复用,它是类设计层次上的复用。
再减少代码量的同时,还能在原有类的基础上扩展新的功能。
被继承的叫基类或父类,得到继承的类叫派生类或子类。
子类可以继承父类的数据和方法。
因为类的方法都存放再代码段,所以继承的概念在内存层面是数据之间的继承。
定义
语法如下
class a
{
//......
};
class b : public a
{
//......
}
public是继承方式,继承方式有如下几种
共有继承:public
保护继承:protected
私有继承:private
继承方式和访问限定符的关系如下
|
类成员
/
继承方式
|
public
继承
|
protected
继承
|
private
继承
|
|
父类的
public
成员
|
子类是public成员
|
子类是protected
成员
|
子类是private
成员
|
|
父类的protected
成员
|
子类是protected
成员
|
子类是protected
成员
|
子类是private
成员
|
|
父类的private
成
员
|
在子类中不可见
|
在子类中不可见
|
在子类中不可见
|
赋值
子类对象可以给父类对象赋值,父类对象不能给子类对象赋值
子类对象可以赋值给父类的对象 / 父类的指针 / 父类的引用
子类是继承父类的数据,父类有的子类一定有,子类有的父类不一定有
形象示意图

这种赋值更形象化的说法叫——切片
作用域

如下是测试代码,
有兴趣的可以粘到编译器上运行一下
// Student的_num和Person的_num构成隐藏关系,可以看出这样代码虽然能跑,但是非常容易混淆
class Person
{
protected :
string _name = "小李子"; // 姓名
int _num = 111; // 身份证号
};
class Student : public Person
{
public:
void Print()
{
cout<<" 姓名:"<<_name<< endl;
cout<<" 身份证号:"<<Person::_num<< endl;
cout<<" 学号:"<<_num<<endl;
}
protected:
int _num = 999; // 学号
};
void Test()
{
Student s1;
s1.Print();
};
// B中的fun和A中的fun不是构成重载,因为不是在同一作用域
// B中的fun和A中的fun构成隐藏,成员函数满足函数名相同就构成隐藏。
class A
{
public:
void fun()
{
cout << "func()" << endl;
}
};
class B : public A
{
public:
void fun(int i)
{
A::fun();
cout << "func(int i)->" <<i<<endl;
}
};
void Test()
{
B b;
b.fun(10);
};
子类的默认成员函数
关于常用的默认成员函数可参考如下两篇文章
子类不能显式的定义,只能调用父类的构造,析构等默认成员函数
构造函数:如果父类不提供默认构造,需要在子类的初始化列表显式调用
拷贝构造:子类必须显式调用符类的拷贝构造
operator=:子类必须显式调用父类的operator=
析构:子类不能显式的调用父类的析构函数,不然会报错
继承与友元
父类与其他类或函数的友元关系不能传递给子类
继承与静态成员
菱形继承
单继承::一个子类只有一个直接父类时称这个继承关系为单继承
多继承:一个子类有两个或以上直接父类时称这个继承关系为多继承
多继承的语法:
class 父类类名 :继承方式 子类类名, 继承方式 子类类名...... 中间用逗号分隔

菱形继承:菱形继承是多继承的一种特殊情况

菱形继承是把同一个父类的数据继承了多次,这会造成数据冗余和二义性的问题
菱形虚拟继承
为了解决菱形继承的问题,C++用菱形虚拟继承来解决数据冗余和二义性的问题
语法:
class 父类 : virtual public 子类
virtual是关键字,说明该继承是虚拟继承
虚拟继承的位置(小编把情况搞复杂让大家理解清楚):
红线的继承需要虚拟继承,下面是虚拟继承可以出现的位置
原理
虚拟继承是怎么解决数据冗余和二义性的呢
问题:
子类可以继承父类的数据和方法,由于类的方法都存放在代码段,在内存层面是数据之间的继承。菱形继承导致的问题是因为父类的数据被继承了多次,在内存中一份数据就被储存了多次,同名的变量会造成二义性。
解决:
虚拟继承就是通过上述方法让多个父类和一个子类管理一份数据而不是同名的多份数据。
小编用如下代码调试,带大家感受一下
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;
return 0;
}
上述代码的示意图如下





被折叠的 条评论
为什么被折叠?



