类的继承与派生
热身:
例:
设计一个Person类,代表一个人的基本属性,再设计一个学生类Student,继承Person类,增加学生学号的属性。输出学生信息。
#include <iostream>
#include <string>
using namespace std;
class Person
{
private:
string name;
string sex;
int age;
public:
Person() {}
Person(string,string,int);
void disPlay();
}; //Person基类,有name,sex,age属性
class Student:private Person
{
private:
int num;
Person teacher; //在派生类中有子对象
public:
Student() {}
Student(string,string,int,int ,string ,string,int);
void disPlay1();
void disPlayTeacher()
{
cout<<"teacher"<<endl;
teacher.disPlay();
cout<<endl;
}
}; //Student派生类,新增num学号属性
void Person::disPlay()
{
cout<<"name="<<name<<endl;
cout<<"sex="<<sex<<endl;
cout<<"age="<<age<<endl;
}
Person::Person(string name,string sex,int age)
{
this->name = name;
this->sex = sex;
this->age = age;
}
Student::Student(string name1,string sex1,int age1,int num,string name2,string sex2,int age2):
Person(name1,sex1,age1),teacher(name2,sex2,age2 )
{
this->num = num;
} //派生类的构造函数格式(注意基类和子对象)
void Student::disPlay1()
{
cout<<"student"<<endl;
disPlay();
cout<<"num="<<num<<endl;
cout<<endl;
}
int main()
{
Student st("huahua","girl",19,121205,"fangfang","boy",20);
st.disPlay1();
st.disPlayTeacher(); //输出学生信息
return 0;
}
类的继承:一个新类从已有的类那里获得其已有的特性。
类的派生:已有的类(父类)产生一个新的子类。
单继承:一个派生类只有一个基类。
多继承:一个派生类有两个或多个基类。
形式:
class 派生类名: [继承方式] 基类名
{
派生类增加成员;
};
(1).派生类把基类全部成员,不包括构造函数和析构函数。
(2).调整从基类接收的成员。派生类中声明一个与基类成员同名的成员,则派生类中的新成员则会覆盖基类同名成员。如果是成员函数,则应函数名函数类型参数个数相同。
(3).派生类继承了基类的所有有数据成员和成员函数,并可对成员作必要的增加或调整。
(4).基类的成员函数只能访问基类成员,不能访问派生类成员。
(5).继承方式:
公用继承:(public)基类的公用成员和保护成员在派生类中保持原有访问属性,其私有成员仍为基类私有。
私有继承:(private)基类的公有成员在派生类中成了私有成员,基类私有成员仍为基类私有。
受保护继承:(protected)基类公用成员和受保护成员在派生类中成了保护成员。(保护成员:不能被外界引用,但可以被派生类的成员引用)
(6).派生类:一部分从基类继承过来,另一部分派生类新增成员。
多级派生时的访问属性
class A { …… }
class B : public A { …… }
class C : protect B { …… }
多级派生,如果都采用公用或受保护方式,最后一级可访问最初基类。如果是私有继承,经过多级后成员或被外界不能访问。
派生类的构造函数和析构函数
构造函数:
派生类构造函数名 (总参数列表):基类构造函数名 (参数列表)
{派生类中新增数据成员初始化语句}
例:
Student::Student(string name,string sex,int age,int num):Person(name,sex,age)
{
this->num = num;
}
析构函数:
即为派生类名前加~,因为不能继承基类的构造函数和析构函数。
有子对象的派生类的构造函数
例:
Student::Student(string name1,string sex1,int age1,int num,string name2,string sex2,int age2):
Person(name1,sex1,age1),teacher(name2,sex2,age2 )
{
this->num = num;
} //派生类的构造函数格式(注意基类和子对象)
多重继承
派生类D,同时继承了A,B,C类
class D:public A,private B,protected C
{ ……}
多重继承派生类的构造函数
派生类构造函数名 (总参数表) :基类1构造函数(参数列表),基类2构造函数(参数列表),基类3构造函数(参数列表)
{ 派生类中新增数据成员初始化 }
多重继承引起的二义性问题
例:
class A
{
public:
int a;
void display();
};
class B
{
public:
int a;
void display();
};
class C:public A,public B
{
public:
int b;
void show();
};
如果定义C的对象c,当调用c.display()时,不能确定是B的还是A的,出问题了。
解决措施:当调用A类的display时,写成c.A ::display(),就会调用A类的函数display。
虚基类
例。Teacher类和Student类的共同基类是Person,Graduate共同继承了Teacher类和Student类,建立一个Graduate对象,输出对象信息
#include <iostream>
#include <string>
using namespace std;
//声明公共类
class Person
{
protected: // 保护成员
string name;
string sex;
int age;
public:
Person(string name,string sex,int age) // 构造函数
{
this->name = name;
this->sex = sex;
this->age = age;
}
};
//声明Person的直接派生类Teacher
class Teacher:virtual public Person // 声明Person为公用继承的虚基类
{
protected:
string title;
public:
Teacher(string name,string sex,int age,string title):Person(name,sex,age)
{
this->title = title;
}
};
// 声明Person的直接派生类Student
class Student:virtual public Person //声明Person为公用继承的虚基类
{
protected: //保护成员
float score;
public:
Student(string name,string sex,int age,float score):Person(name,sex,age) //构造函数
{
this->score = score;
}
};
class Graduate:public Teacher,public Student // Graduate 同时继承了 Teacher和 Student 类
{
private:
float wage;
public:
Graduate(string name,string sex,int age,string title,float score,float wage):
Person(name,sex,age),Teacher(name,sex,age,title),Student(name,sex,age,score)
{
this->wage = wage; //工资
}
void show();
};
void Graduate::show()
{
cout<<"name="<<name<<endl;
cout<<"age="<<age<<endl;
cout<<"sex="<<sex<<endl;
cout<<"score="<<score<<endl;
cout<<"title="<<title<<endl;
cout<<"wage="<<wage<<endl;
}
int main()
{
Graduate gra("feifei","boy",20,"assistant",99,8872.6); //建立Graduate对象
gra.show();
return 0;
}
有人会问,如果一个派生类有多个直接基类,而直接基类又有一个共同的基类,则在最终的派生类中会保留该间接共同基类的数据成员的多分数据成员,不会重复吗?不会,因为虚基类在继承间接共同基类时只保留一份成员。
格式:
class 派生类名 : virtual 继承方式 基类名
基类与派生类之间的转换
只有公共派生类才是基类真正的子类型。
不同数据之间的自动转换和赋值,称为赋值兼容。
派生类可以向基类对象赋值。赋值时派生类舍弃自己的成员,赋值只是对数据成员的赋值,对成员函数不存在赋值问题。方向是单向的,不可逆。如果是派生类向基类的引用赋值,基类的引用不是派生类对象的别名,也不与派生类对象共用一段存储,他是派生类对象基类部分的别名。
继承与组合
在一个类中以另一各类的对象作为数据成员,称为类的组合。