目录
一、多继承的概念
作用:一个子类同时继承多个父类的数据成员和功能函数,提高了代码的复用性。
语法: class 派生类 : 继承方式 基类名,继承方式 基类名 , . . .{
};
例子: 子类: c ,父类 a , 父类 b
class c : public a , public b {
};
//我们定义人类和运动员类是基类,老师类是他们共同的派生类,分别继承他们。
//demo1
#include<iostream>
#include<string.h>
using namespace std;
//人类(基类)
class Person{
public:
Person(){}
private:
char name[15];
int age;
};
//运动员类(基类)
class Athletes{
public:
Athletes(){}
private:
char sport[20]; //运动项目
int medal; //奖牌
};
//老师类(派生类)
class Teacher : public Person, public Athletes
{
public:
Teacher(){}
private:
char subject[10]; //学科
};
int main()
{
Teacher tmp;
}
二、多继承构造函数
1、多继承构造函数执行顺序:按照继承的顺序来执行。
class base_c : public base_a , public base_b;
构造函数执行顺序: base_a -> base_b -> base_c ;
析构函数执行顺序: base_c -> base_b -> base_a ;
2、多继承参数列表的初始化
//初始化格式:子类构造函数(参数1,参数2):父类1(参数1..),父类2(参数2..),...
//注意:下面代码较长,请抓住传递参数和初始化参数的部分阅读。
#include<iostream>
#include<string.h>
using namespace std;
//人类(基类)
class Person{
public:
Person(){}
Person(const char *name,int age):age(age){ //观察如何在子类初始化
strcpy(this->name,name);
}
void show_Person(){
cout << "姓名:" << this->name << " 年龄:" << age << endl;
}
private:
char name[15];
int age;
};
//运动员类(基类)
class Athletes{
public:
Athletes(){}
Athletes(const char *sport,int medal):medal(medal){ //观察如何在子类初始化
strcpy(this->sport,sport);
}
void show_Athletes(){
cout << "运动项目:" << this->sport << " 奖牌:" << medal << endl;
}
private:
char sport[20]; //运动项目
int medal; //奖牌
};
//老师类(派生类)
class Teacher : public Person, public Athletes
{
public:
Teacher(){}
Teacher(const char *subject,const char *name,int age,const char *sport,int medal):Person(name,age),Athletes(sport,medal){ //重点:初始化两个基类的方法
strcpy(this->subject,subject);
}
void show_Teacher(){
show_Person();
cout << "学科:" << subject << endl;
show_Athletes();
}
private:
char subject[10]; //学科
};
int main()
{ //传参需要传递两个基类的参数
Teacher tmp("化学","小芳",23,"世界杯",5); //科目,姓名,年龄,运动项目,奖牌数
tmp.show_Teacher();
}
三、多级继承
1、作用:一个子类同时继承多级父类的数据成员和功能函数,提高代码的复用性。
2、语法:
class 爷爷类 {
};
class 父类 : 继承方式 爷爷类 {
};
class 子类 : 继承方式 父类{
};
例子:
class base_a ;
class base_b : public base_a ;
class base_c : public base_b;
// base_c 同时拥有了 base_a 和 base_b 的数据成员和功能函数。
3、多级继承的构造函数
class base_a
class base_b : public base_a
class base_c : public base_b
构造函数的执行顺序: base_a -> base_b -> base_c
析构函数的执行顺序: base_c -> base_b -> base_a
4、多级继承的参数列表初始化:重点是参数列表如何初始化
#include<iostream>
#include<string.h>
using namespace std;
//人类(爷爷类)
class Person{
public:
Person(){}
Person(const char *name,int age):age(age){
strcpy(this->name,name);
}
void show_Person(){
cout << "姓名:" << this->name << " 年龄:" << age << endl;
}
private:
char name[15];
int age;
};
//运动员类(父亲)
class Athletes : public Person{
public:
Athletes(){}
Athletes(const char *sport,int medal, const char *name,int age):medal(medal),Person(name,age){
strcpy(this->sport,sport);
}
void show_Athletes(){
cout << "运动项目: " << this->sport << " 奖牌数:" << medal << endl;
}
private:
char sport[50]; //运动项目
int medal; //奖牌
};
//老师类(子类)
class Teacher : public Athletes
{
public:
Teacher(){}
Teacher(const char *subject, const char *name,int age,const char *sport,int medal):Athletes(sport,medal,name,age){
strcpy(this->subject,subject);
}
void show_Teacher(){
show_Person();
cout << "学科:" << subject << endl;
show_Athletes();
}
private:
char subject[10]; //学科
};
int main()
{
Teacher tmp("数学","小红",25,"唱跳,rap,篮球",7); //科目,姓名,年龄,运动项目,奖牌数
tmp.show_Teacher();
}
//从子类传递参数->父类传递参数给->爷爷类
四、菱形继承
1、多个子类继承一个父类会产生重复调用,产生多个父类构造函数。 (因为系统不知道调用哪个的构造函数,所有就会创建两个)。
2、多个子类继承一个父类会产生重复调用,产生多个父类构造函数。
#include<iostream>
using namespace std;
//菱形继承构造函数的遍历相当于二叉树的前序遍历,根左右。
构造函数:遍历顺序base->base_a->base->base_b->base_c
析构函数:遍历顺序base_c->base_b->base->base_a->base(和构造调用相反)
此方法会产生二义性,导致有两个base(利用虚继承解决)
//基类
class base{
public:
base() {cout << "构造函数base\n";}
~base(){cout << "析构函数base\n";}
void show(){
cout << "show() base_a" << endl;
}
};
//多级继承(派生类)
class base_a : public base{
public:
base_a() {cout << "构造函数base_a\n";}
~base_a(){cout << "析构函数base_a\n";}
};
//多级继承(派生类)
class base_b : public base{
public:
base_b() {cout << "构造函数base_b\n";}
~base_b(){cout << "析构函数base_b\n";}
};
//多继承(派生类的子类)
class base_c : public base_a, public base_b{
public:
base_c() {cout << "构造函数base_c\n";}
~base_c(){cout << "析构函数base_c\n";}
void show(){
cout << "show() base_c" << endl;
}
};
int main()
{
base_c order;
order.show();
cout << "程序结束\n";
}
3、解决二义性的方法:
(1)在最后派生的类中编写接口,隐藏基类的功能方法,屏蔽二义性。
(2)利用域操作符指定使用的基类接口 。使用方法:声明对象 . 类 : : 函数 。
(3)利用虚继承解决二义性 (最完美!)。
格式1: class 类名 :virtual 继承方式 类名,virtual 继承方式 类名 ...
格式2: class 类名 :继承方式 virtual 类名,继承方式 virtual 类名...(编译通过的)。
#include<iostream>
using namespace std;
//构造函数:遍历顺序base->base_a->base->base_b->base_c
//析构函数:遍历顺序base_c->base_b->base->base_a->base(和构造调用相反)
//二义性解决方法
//解决方法:利用虚函数virtual
//基类
class base{
public:
base() {cout << "构造函数base\n";}
~base(){cout << "析构函数base\n";}
};
//多级继承(派生类)
class base_a : virtual public base{
public:
base_a() {cout << "构造函数base_a\n";}
~base_a(){cout << "析构函数base_a\n";}
};
//多级继承(派生类)
class base_b : virtual public base{
public:
base_b() {cout << "构造函数base_b\n";}
~base_b(){cout << "析构函数base_b\n";}
};
//多继承(派生类的子类)
class base_c : public base_a, public base_b{
public:
base_c() {cout << "构造函数base_c\n";}
~base_c(){cout << "析构函数base_c\n";}
};
int main()
{
base_c order;
cout << "程序结束\n";
}
五、虚继承
1、虚继承:主要解决棱形继承时,出现的内存访问冲突和二义性问题。继承方式可以缺省,默认为私有继承。
2、虚继承实际上就是系统创建的一个虚表,当类中含有虚方法时,系统就会创建一个虚表,所有的虚方法都是存放在虚表中的。(可实现多态)。
3、证明虚表的存在:
当一个类中有一个或多个虚拟函数那么这个类在创建对象的时候就会创建一个虚表!
虚表就是一个存放虚函数<指针>的表格。