
继承是面向对象三大特性之一、有些类与类之间存在特殊的关系,例如下图中:

我们发现,定义这些类时,下级别的成员除了拥有上一级的共性,还有自己的特性。
这个时候我们就可以考虑利用继承的技术,减少重复代码。
语法:class 子类:继承方式 父类
优点:减少重复代码
子类也叫派生类,父类也叫基类
代码:
- #include
- using namespace std;
- class person { //定义person基类
- public:
- int age;
- int height;
- int weight;
- string name;
-
- void show() {
- cout << "age=" << age << endl;
- cout << "height=" << height << endl;
- cout << "weight=" << weight << endl;
- cout << "name=" << name << endl;
- }
- };
-
- class women :public person {
- public:
- string xingbie;
- void shou_x() {
- cout << "xingbie=" << xingbie<
- }
- };
-
- void fun() {
- women p;
- p.age = 18;
- p.height = 180;
- p.name = "tom";
- p.weight = 160;
- p.xingbie = "女";
- p.show();
- p.shou_x();
- }
- int main() {
- fun();
- return 0;
- }

派生类中的成员,包含两大部分:
1.类是从基类继承过来的,-类是自己增加的成员。
2.从基类继承过过来的表现其共性,而新增的成员体现了其个性。
二.继承方式
继承方式:
public: 公有继承
protected:保护继承
private: 私有继承
代码:
- #include
- using namespace std;
- class father {
- public:
- int A;
- protected:
- int B;
- private:
- int C;
- };
-
- class son1 :public father { //公有继承
- public:
- void fun() {
- cout << "A=" << A << endl; //公有变为公有
- cout << "B=" << B << endl; //保护变为保护
- //cout << "C=" << C << endl;//私有不可访问
- }
- };
-
- class son2 :protected father { //保护继承
- public:
- void fun() {
- cout << "A=" << A << endl; //公有变为保护
- cout << "B=" << B << endl; //保护变为保护
- //cout << "C=" << C << endl;//私有不可访问
- }
- };
-
-
- class son3 :private father { //私有继承
- public:
- void fun() {
- cout << "A=" << A << endl; //公有变为私有
- cout << "B=" << B << endl; //保护变为私有
- //cout << "C=" << C << endl;//私有不可访问
- }
- };
-
-
- void fun() {
- son1 p1;
- son2 p2;
- son3 p3;
- p1.A = 10;
- p1.fun();
- }
- int main() {
- fun();
- return 0;
- }

私有成员全不见,公不变,保全保,私全私。
三.继承中的对象模型
继承中,基类私有变量虽然访问不到,但是已经被继承,只是被隐藏了。
代码:
- #include
- using namespace std;
- class father {
- public:
- int A;
- protected:
- int B;
- private:
- int C;
- };
- class son :private father {
- public:
- int age;
- };
- int main() {
- cout << sizeof(son) << endl;
- return 0;
- }
四.继承构造和析构顺序
子类继承父类时,会先创建一个父类。析构的顺序和构造顺序正好相反。
代码:
- #include
- using namespace std;
- class father {
- public:
- father() {
- cout << "father的构造哈数" << endl;
- }
- ~father() {
- cout << "father的析构函数" << endl;
- }
- };
- class son :public father {
- public:
- son() {
- cout << "son的构造函数" << endl;
- }
- ~son() {
- cout << "son的析构函数" << endl;
- }
- };
- void fun() {
- son a;
- }
- int main() {
- fun();
- return 0;
- }

五.继承同名成员处理方式
当基类中的成员变量以及成员函数,和派生类的成员变量和函数重名时,基类默认调用派生类的成员函数和成员变量。要想调用基类的成员函数和成员变量,需要加上基类的作用域;
代码:
- #include
- using namespace std;
- class father {
- public:
- int A;
- father() {
- A = 999;
- }
- void fun() {
- cout << "father的fun调用" << endl;
- }
- void fun(int a) {
- cout << "father的fun调用" << ' ' << a << endl;
- }
- };
- class son :public father{
- public:
- int A;
- son() {
- A = 99;
- }
- void fun() {
- cout << "son的fun调用" << endl;
- }
- void fun(int a) {
- cout << "father的fun调用" << ' ' << a << endl;
- }
- };
- void fun() {
- son p;
- cout << "son" << ' ' << p.A << endl;
- cout << "father" << ' ' << p.father::A << endl;
- p.fun();
- p.fun(11);
- p.father::fun();
- p.father::fun(90);
- }
- int main() {
- fun();
- return 0;
- }
如果派生类中出现和基类重名的成员函数,那么派生类会隐藏基类全部重名的成员函数。需要注意的是,本来可以按照函数重载区分,却被派生类隐藏的情况:
代码:
- #include
- using namespace std;
- class father {
- public:
- int A;
- father() {
- A = 999;
- }
-
- void fun() {
- cout << "father的fun调用" << endl;
- }
- void fun(int a,int b) {
- cout << "father的fun调用" << ' ' << a << endl;
- }
- };
- class son :public father{
- public:
- int A;
- son() {
- A = 99;
- }
- void fun() {
- cout << "son的fun调用" << endl;
- }
- };
- void fun() {
- son p;
- cout << "son" << ' ' << p.A << endl;
- cout << "father" << ' ' << p.father::A << endl;
- p.fun();
- p.fun();
- p.father::fun();
- //p.fun(90,89);//报错
- p.father::fun(89, 123);
- }
- int main() {
- fun();
- return 0;
- }
六.继承同名static成员处理方式
当重名的成员变量和函数是static时,需要注意通过类名来调用的方式
代码:
- #include
- using namespace std;
- class father {
- public:
- static int A;
- static void fun() {
- cout << "father的fun调用" << endl;
- }
- void fun(int a) {
- cout << "father的fun调用" << a<<' ' << endl;
- }
- };
- int father::A=10; //static成员变量,类内声明,类外定义
- class son :public father {
- public:
- static int A;
- static void fun() {
- cout << "son的fun调用" << endl;
- }
- };
- int son::A = 20;
- void fun() {
- son p;
- //1.利用对象调用成员变量和函数
- cout << p.A << endl;
- cout << p.father::A << endl;
- p.fun();
- p.father::fun();
-
- cout << "**************************" << endl;
- //2.利用类名调用成员变量和函数
- cout << son::A << endl;
- cout << father::A << endl;
- cout << son::father::A << endl;
-
- son::fun();
- father::fun();
- son::father::fun();
- //father::fun(10); //报错,此方法只能调用static类型
-
-
- }
- int main() {
- fun();
- return 0;
- }

七.多继承语法
C++中允许一个类继承多个类
语法: class子类∶继承方式父类1,继承方式父类2...
多继承可能会引发父类中有同名成员出现,需要加作用域区分
C++实际开发中不建议用多继承
代码:
- #include
- using namespace std;
- class base1 {
- public:
- int A;
- base1() {
- A = 10;
- cout << "base1构造函数调用" << endl;
- }
- };
-
-
- class base2 {
- public:
- int A;
- base2() {
- A = 20;
- cout << "base2构造函数调用" << endl;
- }
- };
-
- class son :public base1, public base2 {
- public:
- int B;
- int C;
- son() {
- B = 100;
- C = 200;
- cout << "son构造函数调用" << endl;
- }
- };
-
- void fun() {
- son b;
- cout << b.base1::A << endl;
- cout << b.base2::A << endl;
- cout << b.B << endl;
- cout << b.C << endl;
- }
- int main() {
- fun();
- return 0;
- }

注意构造函数的调用顺序,父亲1先调用,父亲2再调用,最后son调用
总结:多继承中如果父类中出现了同名情况,子类使用时候要加作用域。
八.菱形继承
菱形继承概念:
两个派生类继承同一个基类
又有某个类同时继承者两个派生类
这种继承被称为菱形继承,或者钻石继承

1.羊继承了动物的数据,驼同样继承了动物的数据,当羊驼使用数据时,就会产生二义性。
2.羊驼将动物的数据继承了两份,其实我们应该清楚,这份数据我们只需要—份就可以。
代码:
- #include
- using namespace std;
- class dongwu {
- public:
- int A;
- };
- class yang :public dongwu {};
- class tuo:public dongwu {};
- class son :public tuo, public yang {};
- void fun() {
- son p;
- p.yang::A = 100;
- p.tuo::A = 200;
- //当菱形继承,两个父亲拥有相同名的成员时,要加作用域加以区分;
- cout << p.yang::A << endl;
- cout << p.tuo::A << endl;
- }
- int main() {
- fun();
- return 0;
- }

此时的继承情况是,这样的。

利用虚继承,可以解决菱形继承的问题(两份相同的数据,浪费内存)
代码:
- #include
- using namespace std;
- class dongwu {
- public:
- int A;
- };
- //virtual虚继承,dongwu称为虚基类
- class yang :virtual public dongwu {};
- class tuo:virtual public dongwu {};
- class son :public tuo, public yang {};
- void fun() {
- son p;
- yang p1;
- tuo p2;
- p.yang::A = 100;
- p.tuo::A = 200;
- p1.A = 90;
- p2.A = 190;
- //当菱形继承,两个父亲拥有相同名的成员时,要加作用域加以区分;
- cout << p.yang::A << endl;
- cout << p.tuo::A << endl;
- cout << p1.A << endl;
- cout << p2.A << endl;
-
- }
- int main() {
- fun();
- return 0;
- }

继承时只继承一份,此时son继承的是两个虚基类表的指针,虚基类表中存储的是到成员的偏移量。
总结:
·菱形继承带来的主要问题是子类继承两份相同的数据,导致资源浪费以及毫无意义·利用虚继承可以解决菱形继承问题