2.继承机制
文章目录
2.1 继承与派生的概念
继承是指在已有类的或称为基类的基础上创建新类,这个新类就是派生类。
- 单继承:由一个基类派生的类
- 多继承:由两个或多个基类派生的类
2.2 继承类的声明
类的单继承声明格式如下;
class 派生类名:继承方式 基类名{
派生类成员声明
}
案例 基类Person和派生类Student
派生类自动的包含了基类的成员,包括所有的数据和操作,而且它还可以增加自身新的成员。
class Person {
protected:
string name;
int age;
public:
void setPerson(string n,int a) {
name = n;
age = a;
}
void showPerson() {
cout << "name: " << name << endl;
cout << "age: " << age << endl;
}
};
class Student:public Person {
int grade;
public:
void setStudent(string n, int a, int g) {
setPerson(n, a);
grade = g;
}
void showStudent() {
showPerson();
cout << "grade: " << grade << endl;
}
};
int main()
{
Student s;
s.setStudent("Tom", 12, 5);
s.showStudent();
return 0;
}
2.3 派生类的访问控制
(1)共有继承
class 派生类:public基类{
//…
}
(2)保护继承
class 派生类:protected基类{
//…
}
(3)私有继承
class 派生类:private基类{
//…
}
基类成员在派生类中的访问属性
在基类中访问属性 | 继承方式 | 在派生类中的访问属性 |
---|---|---|
private | public | 不可直接访问 |
private | private | 不可直接访问 |
private | protected | 不可直接访问 |
public | public | public |
public | private | private |
public | protected | protected |
protected | public | protected |
protected | private | private |
protected | protected | protected |
public>protected>private>不可直接访问
2.4 继承机制下的构造函数与析构函数
在继承机制中,基类的构造函数和析构函数是不能继承的。
派生类的构造函数负责对来自基类数据成员和新增加的数据成员进行初始化。
所以,在执行派生类的构造函数时,需要调用基类的构造函数,并提供基类构造函数所需的参数。
派生类构造函数执行顺序
- 基类的构造函数;
- 对象成员的构造函数(如果有的话),有多个时按声明的顺序;
- 派生类的构造函数。
派生类析造函数执行顺序
- 派生类的析构函数;
- 对象成员的析构函数(如果有的话),有多个时与声明的顺序相反;
- 基类的虚构函数
2.5 多继承
多继承下派生类的声明格式如下:
class 派生类名:继承方式1 基类名1,继承方式2 基类名2...
{
派生类类体;
}
继承方式:public、protected和private之一,
如果缺省则是private。
案例 学生类+在职人员=在职学生类
protected:
string name;
string Id;
char gender;
public:
Student(string name,string Id,char gender) {
this->name = name;
this->Id = Id;
this->gender = gender;
}
void showStudent() {
cout << "name: " << name << endl;
cout << "Id: " << Id << endl;
cout << "gender: " << gender << endl;
}
};
class Employee {
protected:
string name;
string job;
public:
Employee(string name, string job) {
this->name = name;
this->job = job;
}
void showEmployee() {
cout << "name: " << name << endl;
cout << "job: " << job << endl;
}
};
class StudentHasJob :public Student, public Employee {
public:
StudentHasJob(string name,string Id,char gender,string job):Student(name,Id,gender),Employee(name,job){
}
void showStudentHasJob() {
/*cout << "name: " << name << endl;
cout << "Id: " << Id << endl;
cout << "gender: " << gender << endl;*/
showStudent();
cout << "job: " << job << endl;
}
};
int main()
{
StudentHasJob s("Jom","202200201089",'m',"工程师");
s.showStudentHasJob();
return 0;
}
2.6 虚基类和赋值兼容规则
2.6.1 基类成员名的限定访问和名字覆盖
若多个基类中定义有同名成员,则派生类对这些同名的访问可能存在冲突。
为避免可能出现的成员访问冲突,需要用成员名限定的方法显式地指定要访问的成员。
基类名::成员名
void showStudentHasJob() {
cout << "name: " << Student::name << endl;//成员名限定
cout << "Id: " << Id << endl;
cout << "gender: " << gender << endl;
//showStudent();
cout << "job: " << job << endl;
}
2.6.2 虚基类的概念(菱形继承)
派生类对象中存在基类成员的多个副本(菱形继承)。
定义虚基类的格式如下:
class 派生类名:virtual 继承方式 基类名称{
...
};
2.6.3 虚基类的初始化
(1)所有从虚基类直接或间接派生的类必须在该类构造函数的成员初始化列表列出对虚基类构造函数的调用,但是只有实际构造对象的类的构造函数才会引发对虚基类构造函数的调用,而其他基类在成员初始化列表中对虚基类构造函数的调用都会被忽略,从而保证了派生类对象中虚基类成员只会被初始化一次。
(2)若某类构造函数的成员初始化列表中同时列出对虚基类构造函数和非虚类构造函数的调用,则会优先执行虚基类的构造函数。
class Person {
protected:
string name;
int age;
public:
Person(string name, int age) {
this->name = name;
this->age = age;
cout << "Person的构造函数" << endl;
}
void showPerson() {
cout << "name: " << name << endl;
cout << "age: " << age << endl;
}
};
class Student: virtual public Person{
protected:
char gender;
public:
Student(string name,int age,char gender):Person(name,age) {
this->gender = gender;
cout << "Student的构造函数" << endl;
}
void showStudent() {
showPerson();
cout << "gender: " << gender << endl;
}
};
class Employee:virtual public Person{
protected:
string job;
public:
Employee(string name, int age,string job):Person(name,age) {
this->job = job;
cout << "Employee的构造函数" << endl;
}
void showEmployee() {
showPerson();
cout << "job: " << job << endl;
}
};
class StudentHasJob :public Student, public Employee {
public:
StudentHasJob(string name,int age,char gender,string job):Student(name,age,gender),Employee(name,age,job),Person(name,age){
cout << "StudentHasJob的构造函数" << endl;
}
void showStudentHasJob() {
showStudent();
cout << "job: " << job << endl;
}
};
int main() {
StudentHasJob s("Jom",20,'m',"工程师");
s.showStudentHasJob();
return 0;
}
2.6.4 赋值兼容规则
(1)基类对象可以赋值给基类对象,也可以把派生类对象赋值给基类对象。
(2)基类指针可以指向基类对象,也可以指向派生类对象。
(3)基类引用可以指向基类对象,也可以指向派生类对象。
class Shape {
protected:
int x, y;
public:
Shape(int xx = 0, int yy = 0) {
x = xx;
y = yy;
}
void show() {
cout << "图形的中心是:" << "(" << x << "," << y << ")" << endl;
}
void Area() {
cout << "不知道什么图形,不知道面积" << endl;
}
};
class Circle:public Shape {
int radius;
public:
Circle(int x, int y, int r) :Shape(x, y) {
radius = r;
}
void show() {
cout << "该图形是圆" << endl;
Shape::show();
}
void Area() {
cout << "圆的面积是:" << 3.14 * radius * radius << endl;
}
};
int main() {
Shape s1, s2(2, 2);//建立了两个基类对象s1和s2
s1 = s2;
s1.show();
Circle c(30, 30, 8);//建立了一个对象圆,中心点在(3,3),半径是8
s1 = c;//基类的对象等于派生类的对象
s1.show();
Shape* s3 = &s2;//基类的指针指向基类的对象
s3->show();
Shape* s4 = &c;//基类的指针指向派生类的对象
s4->show();
Shape& s5 = s2;//基类的引用等于基类的对象
s5.show();
Shape& s6 = c;//基类的引用等于派生类的对象
s6.show();
s6.Area();//不知道是什么图形,不知道面积
return 0;
}