类的继承:解决代码的复用
已存在的类称为“父类”或“基类”
新建立的类称为“子类”或“派生类”
一个类从已有的类中获取已有特性叫做类的继承
从已有的类产生一个新的子类叫做类的派生
一个派生类只从一个基类中派生,这称作单继承
派生类是基类的具体化,基类是派生类的抽象化
继承方式:公用继承(public)、私有继承(private)、受保护继承(protected),默认为私有继承
公用继承:基类的公用、私有成员在派生类中保持原有的访问属性,私有成员仍为基类私有
私有继承:基类的公用、保护成员在派生类中成了私有成员,私有成员仍为基类私有
受保护继承:基类的公用、保护成员在派生类中成了保护成员,私有成员仍为基类私有
派生类的构成:从基类中接收成员、调整从基类接收的成员、在声明派生类时增加的成员
多级派生时的访问属性:与上面一致,层层剥选(最常用的还是公有继承)
接下来是一个公有继承的栗子:
#include<iostream>
#include<string>
class Person
{
public:
Person(int age, std::string name)
:_age(age)
, _name(name)
{}
void display()
{
std::cout << "name:" << _name << std::endl;
std::cout << "age:" << _age << std::endl;
}
private:
std::string _name;
int _age;
};
class Student : public Person
{
public:
Student(int age, std::string name,int stuid) :Person(age,name)
, _stuid(stuid)
{}
protected:
int _stuid;
};
class Teacher :public Person
{
public:
Teacher(int age, std::string name,int jobid) : Person(age,name)
//派生类(初始化总表):基类(参数)
, _jobid(jobid)
{}
protected:
int _jobid;
};
int main()
{
Student s(15, "张三", 13);
Teacher t(15, "李四", 12);
s.display();
t.display();
}
当然应该注意的是:派生类后一定是参数的总表
派生类的构造函数和析构函数:
基类的构造函数是不能继承的,所以对基类成员的初始化工作也要由派生类的构造函数承担
有子对象的派生类的构造函数:
1、对基类数据成员初始化
2、对子对象数据成员初始化
3、对派生类数据成员初始化
执行派生类构造函数的顺序:
1、调用基类的构造函数,对基类数据成员初始化
2、调用子对象构造函数,对子对象数据成员初始化
3、调用派生类构造函数,对派生类数据成员初始化
在这里有必要解释一下----子对象: 子对象是对象的对象(可以理解为结构体类型的成员可以是结构体变量)
再来个栗子:
class Student
{
public:
Student(int num,std::string name)
:_num(num)
,_name(name)
{}
void display()
{
std::cout << "num:" << _num << std::endl << "name:" << _name << std::endl;
}
private:
int _num;
std::string _name;
};
class Student1 :public Student
{
public:
Student1(int num, std::string name, int n1,std::string name1, int age, std::string addr) :Student(age, name),monitor(n1,name1)
, _age(age)
, _addr(addr)
{}
void show()
{
std::cout << "该学生是:" << std::endl;
display();
{
std::cout << "age:" << _age << std::endl;
std::cout << "addr:" << _addr << std::endl;
}
}
void show_monitor()
{
std::cout << "Class monitor is:" << std::endl;
monitor.display();
}
private:
Student monitor;//定义子对象monitor
int _age;
std::string _addr;
};
int main()
{
Student1 s1(10010, "张三", 100001, "李四", 19, "115 beijing road,shanghai");
s1.show();
s1.show_monitor();
return 0;
}
代码说明一切。.
派生类构造函数的特殊形式:
1)不需要对派生类新增的成员函数进行任何初始化操作时,派生类的构造函数的函数体可以为空,即构造函数为空函数
2)基类中没有定义构造函数,或定义无参的构造函数,在定义派生类构造函数时可以不写基类的构造函数
多重继承:一个派生类有两个或多个基类,派生类从两个或多个基类中继承所需的属性
class D:public A,private B,protected C
派生类构造函数名(总参数表):基类1构造函数(参数表),基类2构造函数(参数表)
{
派生类中新增数据成员初始化
}
多重继承的二义性:不同基类中有同名的数据成员
引用类的直接派生类名来指出访问哪个数据成员 c1.A::a = 3
为了解决多重继承的二义性,C++引入了虚基类
虚基类:在继承间接共同基类时只保存一份成员
虚基类并不是在声明基类时声明的,而是在声明派生类时,指定继承方式时声明的
虚基类的初始化:
如果虚基类中定义了带参数的构造函数,而且没有定义默认构造函数,则在其所有派生类中,通过构造函数的初始化表对虚基类进行初始化。
注意:在最后的派生类中不仅要负责对其直接基类进行初始化,还要负责对虚基类初始化
因为多重继承存在二义性,因此如果能用单一继承解决的问题就不要使用多重继承
来个虚基类的简单栗子:
class Person
{
public:
Person(string name, int age, char sex)
:_name(name)
, _age(age)
, _sex(sex) {}
protected:
string _name;
int _age;
char _sex;
};
class Teacher :virtual public Person
{
public:
Teacher(string name, int age, char sex, string title) :Person(name, age, sex)
, _title(title)
{}
protected:
string _title;
};
class Student :virtual public Person
{
public:
Student(string name, int age, char sex, float score) :Person(name, age, sex)
, _score(score)
{}
protected:
float _score;
};
class Graduate :public Teacher, public Student
{
public:
Graduate(string name, char sex, int age, string title, float score, float wage)
:Person(name, sex, age), Teacher(name, sex, age, title), Student(name, sex, age, score)
, _wage(wage)
{}
void show()
{
cout << "name:" << _name << endl;
cout << "sex:" << _sex << endl;
cout << "age:" << _age << endl;
cout << "title:" << _title << endl;
cout << "score:" << _score << endl;
cout << "wage:" << _wage << endl;
}
private:
float _wage;//津贴
};
int main()
{
Graduate g1("王力",'f', 24, "assistant", 89.5, 1200);
g1.show();
return 0;
}
虚继承就是将类的重复部分保留一份,达到去重的效果,此代码中原本Student类和Teacher类中都继承了Person类的成员,再由Graduate类继承,原本应该是有两份Person类成员的,但是这里是使用虚继承,因此重复部分只保留一份,虚继承关键字virtual。