c++类的继承
1.1继承与派生
派生类是基类的具体化,而基类是派生类的抽象
一个派生类只从一个基类中派生,称为单继承
一个派生类有多个基类,称为多重继承
1.2派生类的声明方式
固定格式:
class 派生类名:[继承方式] 基类名
{
派生类新增的成员
}
1.3派生类成员的访问方式
构造一个派生类包括以下三个工作:
1.从基类中接受成员。
派生类不加选择的继承基类的全部成员(不包括构造函数与析构函数)。
表面上父类中的私有成员无法访问,是因为父类中的私有成员被编译器隐藏,因此只是访问不到,但确实被继承
2.调整从基类的成员
我们无法对接受什么成员做选择,但可以对这些成员的属性做某些调整,即公用继承,私有继承,保护继承。
可以在派生类中声明一个与基类成员同名的成员,或者同名的成员函数,之后会详细讲解
3.在声明派生类时增加的成员
这一部分体现了派生类对基类成员的功能的拓展与个性。
同时,在声明派生类时,一般还应当自己定义派生类的构造函数和析构函数,因为两者不能通过继承得到。
1.4公用继承,私有继承,保护继承
1)共用继承
各成员属性不变,保持原有的继承属性
举例,请阅读下面的程序:
#include<iostream>
using namespace std;
class Student
{
public:
void get_value()//输入基类数据的成员函数
{
cin >> num >> name >> sex;
}
void display()
{
cout << "num:" << num << endl;
cout << "nmae:" << name << endl;
cout << "sex:" << sex << endl;
}
private:
int num;
string name;
char sex;
};
class Student1 :public Student
{
public:
void get_value_1()//输入派生类数据的成员函数
{
cin >> age >> addr;
}
void display_1()
{
//cout << "num:" << num << endl;
//cout << "nmae:" << name << endl;
//cout << "sex:" << sex << endl;
//由于上述数据在基类中私有,所以派生类中的输出函数无法直接调用,
//但是我们可以直接在派生调用基类公有的输出函数。
display();
cout << "age:" << age << endl;
cout << "addr:" << addr << endl;
}
private:
int age;
string addr;
};
int main()
{
Student1 stu1;
stu1.get_value();
stu1.get_value_1();
stu1.display_1();
return 0;
}
2)私有继承
继承的各成员属性全变成私有
举例,还是上面的例子,把公有继承换成私有继承,观察与上一个例子的差异
#include<iostream>
using namespace std;
class Student
{
public:
void get_value()//输入基类数据的成员函数
{
cin >> num >> name >> sex;
}
void display()
{
cout << "num:" << num << endl;
cout << "nmae:" << name << endl;
cout << "sex:" << sex << endl;
}
private:
int num;
string name;
char sex;
};
class Student1 :private Student
{
public:
void get_value_1()
{
get_value();
cin >> age >> addr;
}
void display_1()
{
//此处与上一个例子相似,我们通过派生类的成员函数调用私有基类的公共成员函数,
//此时它时派生类中的私有成员函数,可以被派生类的任何成员函数调用
display();
cout << "age:" << age << endl;
cout << "addr:" << addr << endl;
}
private:
int age;
string addr;
};
int main()
{
Student1 stu1;
//stu1.get_value(); //无法在类外调用派生类中的私有函数
stu1.get_value_1();
stu1.display_1();
return 0;
}
3)受保护的继承
继承的各成员属性全变成被保护类型
ps:保护成员的含义:不能被外界引用,但可以被派生类的成员使用,某种程度上与私有类似。
保护成员与私有成员的差异
从类的角度看,保护成员等价于私有成员。但有一点与私有成员不同,基类中的保护成员可以被派生类的成员函数引用。
基类中的私有成员被派生类继承后,变成了不可访问的成员,派生类中的一切成员均无法访问他们。如果需要在派生类中引用积累的某些成员,应当将基类的这些成员声明为protected,而不是private.
1.5派生类的构造函数与析构函数
为什么需要构造函数?
如果我们需要对类中的数据成员初始化,应该自己定义构造函数
派生类构造函数的一般形式
派生类构造函数名(总参表):基类构造函数名(参数表)
{
派生类中新增数据成员的初始化语句;
}
派生类构造函数的各种形式
- 一般形式
Student1(int n, string nam, char s, int a, string ad) :Student(n, nam, s)
{
age = a;
addr = ad;
}
- 跳过总参表,使用常量或全局变量
Student1(string nam, char s, int a, string ad) :Student(10010, nam, s)
{
age = a;
addr = ad;
}
- 初始化表形式
这种方法利用之前学习过的初始化表
类似于 Box::Box(int h ,int,w ,int len ):height(h) ,width(w) ,length(len){}
这样使函数体为空,更显得简单与方便
Student1(int n, string nam, char s, int a, string ad) :Student(n, nam, s),
age(a),addr(ad){}
1.5.1 简单的派生类的构造函数
#include<iostream>
#include<string>
using namespace std;
class Student
{
public:
Student(int n, string nam, char s)
{
num = n;
name = nam;
sex = s;
}
void display()
{
cout << "num:" << num << endl;
cout << "name:" << name << endl;
cout<<"sex:"<< sex << endl;
}
~Student(){}
protected:
int num;
string name;
char sex;
};
class Student1 :public Student
{
public:
//构造函数
//对于Student(n,nam,s)来说,括号中的参数列表只有参数名而不包括参数类型,
//因为这里不是定义基类构造函数,而是调用基类构造函数,因此这些参数是实参而不是形参。
Student1(int n, string nam, char s, int a, string ad) :Student(n, nam, s)
{
age = a;
addr = ad;
}
void show()
{
//所有数据可以直接访问,因为基类中定义的时保护成员
cout << "num:" << num << endl;
cout << "name:" << name << endl;
cout << "sex:" << sex << endl;
cout << "age:" << age << endl;
cout << "addr:" << addr << endl;
}
~Student1(){}
protected:
int age;
string addr;
};
int main()
{
Student1 stu1(001, "甲", 'm', 20, "china");
Student1 stu2(002, "乙", 'f', 30, "france");
stu1.show();
stu2.show();
return 0;
}
补充: 派生类的构造函数也可以在类外定义
类内只写函数声明:
Student1(int n, string nam, char s, int a, string ad)
类外写函数定义
Student1::Student1(int n, string nam, char s, int a, string ad) :Student(n, nam, s)
{
age = a;
addr = ad;
}
1.5.2 有子对象的派生类的构造函数
应用背景:
当类中的数据成员需要包含类对象时。
#include<iostream>
#include<string>
using namespace std;
class Student
{
public:
Student(int n, string nam, char s)
{
num = n;
name = nam;
sex = s;
}
void display()
{
cout << "num:" << num << endl;
cout << "name:" << name << endl;
cout<<"sex:"<< sex << endl;
}
~Student(){}
protected:
int num;
string name;
char sex;
};
class Student1 :public Student
{
public:
//构造函数
Student1(int n, string nam, char s, int a, string ad,int n1,string nam1,char s1) :Student(n, nam, s),monitor(n1,nam1,s1)
{
age = a;
addr = ad;
}
void show()
{
cout << "num:" << num << endl;
cout << "name:" << name << endl;
cout << "sex:" << sex << endl;
cout << "age:" << age << endl;
cout << "addr:" << addr << endl;
}
void monitor_show()
{
cout << "monitor is:>" << endl;
display();//调用基类中的输出函数
}
~Student1(){}
protected:
Student monitor;//子对象
int age;
string addr;
};
int main()
{
Student1 stu1(001, "甲", 'm', 20, "china",002,"乙",'m');
stu1.show();
stu1.monitor_show();
return 0;
}
1.5.3 多层派生的构造函数
书写注意事项
构造函数,只须写出上一层派生类(即他的直接基类)的构造函数
初始化的顺序
先初始化基类的数据成员,再初始化Student1,最后Student2
#include<iostream>
#include<string>
using namespace std;
class Student
{
public:
Student(int n, string nam, char s)
{
num = n;
name = nam;
sex = s;
}
void display()
{
cout << "num:" << num << endl;
cout << "name:" << name << endl;
cout<<"sex:"<< sex << endl;
}
~Student(){}
protected:
int num;
string name;
char sex;
};
class Student1 :public Student
{
public:
Student1(int n, string nam, char s, int a, string ad,int n1,string nam1,char s1) :Student(n, nam, s),monitor(n1,nam1,s1)
{
age = a;
addr = ad;
}
void show()
{
cout << "num:" << num << endl;
cout << "name:" << name << endl;
cout << "sex:" << sex << endl;
cout << "age:" << age << endl;
cout << "addr:" << addr << endl;
}
void monitor_show()
{
cout << "monitor is:>" << endl;
display();
}
~Student1(){}
protected:
Student monitor;//子对象
int age;
string addr;
};
class Student2 :public Student1
{
public:
Student2(int n, string nam, char s, int a, string ad,int n1, string nam1, char s1,int k) :Student1(n, nam, a, s, ad,n1,nam1,s1)
{
score = k;
}
void show_all()
{
show();
cout << "score:" << score << endl;
}
protected:
int score;
};
int main()
{
Student1 stu1(001, "甲", 'm', 20, "china",003,"丁",'m');
// stu2(002, "乙", 'f', 30, "france");
//Student monitor(004, "丙", 'm');
stu1.show();
cout << endl;
stu1.monitor_show();
cout << endl;
//monitor.display();
//stu2.show();
Student2 stu2(001, "甲", 'm', 20, "china", 003, "丁", 'm', 200);
stu2.show_all();
cout << endl;
stu2.monitor_show();
return 0;
}
1.5.4 派生类的析构函数
继承中构造与析构的顺序
先构造父类,再子类
先析构子类,再父类
1.6继承同名成员处理方法
问题:当子类与父类出现同名的成员,如何通过子类对象,访问到父类中的同名的数据呢?
访问子类同名成员 :直接访问即可
访问父类同名成员:需要加作用域
1.同名成员数据
#include<iostream>
using namespace std;
class Base
{
public:
Base()
{
m_A = 100;
}
int m_A;
};
class Son:public Base
{
public:
Son()
{
m_A = 200;
}
int m_A;
};
int main()
{
Son s;
cout << " Son m_A:" << s.m_A << endl;
cout << " Base m_A:" << s.Base::m_A << endl;
}
2.同名成员函数
如果子类中出现和父类同名的成员函数,子类的同名成员会隐藏掉父类中所有同名成员函数
如果想访问到父类被隐藏的同名成员函数,需要加作用域
#include<iostream>
using namespace std;
class Base
{
public:
Base()
{
m_A = 100;
}
void func()
{
cout << "Base-func函数调用" << endl;
}
void func(int a)
{
cout << a;
}
int m_A;
};
class Son:public Base
{
public:
Son()
{
m_A = 200;
}
void func()
{
cout << "Son-func函数调用" << endl;
}
int m_A;
};
int main()
{
Son s;
s.func();
s.Base::func();
s.Base::func(100);
}
虚基类
c++提供虚基类的方法,使得继承间接共同基类时只保留一份成员
注:为保证虚基类在派生类中只继承了一次,应当在该基类的所有直接派生类声明为虚基类,否则任然会出现对基类的多次继承
举例:
#include<iostream>
using namespace std;
#include<string>
class Person
{
public:
Person(string nam, char s,int a):name(nam),sex(s),age(a){}
protected:
string name;
char sex;
int age;
};
//老师类
class Teacher:virtual public Person
{
public:
Teacher(string nam,char s,int a,string t):Person(nam,s,a),title(t){}
protected:
string title;
};
//学生类
class Student:virtual public Person
{
public:
Student(string nam,char s,int a,float sc):Person(nam,s,a),score(sc){}
protected:
float score;
};
//总类
class Graduate :public Teacher, public Student
{
public:
Graduate(string nam,char s,int a,string t,float sc,float w):Person(nam,s,a),Teacher(nam,s,a,t),Student(nam,s,a,sc),
wage(w){}
void show()
{
cout << name << endl;
cout << age << endl;
cout << title << endl;
cout << sex << endl;
cout << score << endl;
cout << wage << endl;
}
private:
float wage;
};
void test()
{
Graduate g("wang",'f',20, "student",89.5, 2400);
g.show();
}
int main()
{
test();
return 0;
}