一个类可以派生自多个类
,这意味着,它可以从多个基类继承数据和函数。定义一个派生类,我们使用一个类派生列表来指定基类。类派生列表以一个或多个基类命名。
实例:
#include <iostream>
using namespace std;
//基类
class Shape{
protected:
double width;
double height;
public:
void setWidth(double wid){
width=wid;
}
void setHeight(double hei){
height=hei;
}
};
//派生类
class Rectange:public Shape
{
public:
double getArea(){
return (width*height);
}
};
// 程序的主函数
int main( )
{
Rectange rect;
rect.setHeight(23.56);
rect.setWidth(8.45);
cout<<"The Area is:"<<rect.getArea()<<endl;
}
运行结果:
访问控制和继承
派生类可以访问基类中所有的非私有成员。因此基类成员如果不想被派生类的成员函数访问,则应在基类中声明为 private。
我们可以根据访问权限总结出不同的访问类型,如下所示:
访问 | public | protected | private |
同一个类 | yes | yes | yes |
派生类 | yes | yes | no |
外部的类 | yes | no | no |
一个派生类继承了所有的基类方法,但下列情况除外:
- 基类的构造函数、析构函数和拷贝构造函数。
- 基类的重载运算符。
- 基类的友元函数。
继承类型
当一个类派生自基类,该基类可以被继承为 public、protected 或 private 几种类型。继承类型是通过访问修饰符来指定的。
我们几乎不使用 protected 或 private 继承,通常使用 public 继承。当使用不同类型的继承时,遵循以下几个规则:
- 公有继承(public):当一个类派生自公有基类时,基类的公有成员也是派生类的公有成员,基类的保护成员也是派生类的保护成员,基类的私有成员不能直接被派生类访问,但是可以通过调用基类的公有和保护成员来访问。
- 保护继承(protected): 当一个类派生自保护基类时,基类的公有和保护成员将成为派生类的保护成员。
- 私有继承(private):当一个类派生自私有基类时,基类的公有和保护成员将成为派生类的私有成员。
类的多继承
多继承可以看作是单继承的扩展。所谓多继承是指派生类具有多个基类,派生类与每个基类之间的关系仍可看作是一个单继承。
多继承下派生类的定义格式如下:
class <派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,…
{
<派生类类体>
};
其中,<继承方式1>,<继承方式2>,…是三种继承方式:public、private、protected之一。例如:
class A
{
…
};
class B
{
…
};
class C : public A, public B
{
…
};
其中,派生类C具有两个基类(类A和类B),因此,类C是多继承的。按照继承的规定,派生类C的成员包含了基类A, B中成员以及该类本身的成员。
多继承的构造函数
在多继承的情况下,派生类的构造函数格式如下:
<派生类名>(<总参数表>):<基类名1>(<参数表1>),<基类名2>(<参数表2>),…
<子对象名>(<参数表n+1>),…
{
<派生类构造函数体>
}
其中,<总参数表>中各个参数包含了其后的各个分参数表。
多继承下派生类的构造函数与单继承下派生类构造函数相似,它必须同时负责该派生类所有基类构造函数的调用。同时,派生类的参数个数必须包含完成所有基类初始化所需的参数个数。
派生类构造函数执行顺序是先执行所属基类的构造函数,再执行派生类本身构造函数,处于同一层次的各基类构造函数的执行顺序取决于定义派生类时所指定的各基类顺序,与派生类构造函数中所定义的成员初始化列表的各项顺序无关。也就是说,执行基类构造函数的顺序取决于定义派生类时基类的顺序。可见,派生类构造函数的成员初始化列表中各项顺序可以任意地排列。
实例:
#include <iostream>
using namespace std;
//类的多继承
//基类1
class B1{
public:
B1(){
cout<<"The Constructor of B1"<<endl;
}
void print(){
cout<<"The function of B1"<<endl;
}
};
//基类2
class B2{
public:
B2(){
cout<<"The Constructor of B2"<<endl;
}
void print(){
cout<<"The function of B2"<<endl;
}
};
//基类3
class B3{
public:
B3(){
cout<<"The Constructor of B3"<<endl;
}
void print(){
cout<<"The function of B3"<<endl;
}
};
//派生类
class A:public B3,public B1,public B2{
public:
A(){
cout<<"The Constructor of A"<<endl;
}
void print(){
B1::print();
B2::print();
B3::print();
cout<<"The function of A"<<endl;
}
};
// 类的多继承,主函数
int main( )
{
A aa;
aa.print();
}
在该程序中,作用域运算符::用于解决作用域冲突的问题。在派生类A中的print()函数的定义中,使用了B1::print;和B2::print();语句分别指明调用哪一个类中的print()函数,这种用法应该学会。
在上例出现了二义性问题,派生类A的两基类B1和B2中都有一个成员函数print()。如果在派生类中访问print()函数,到底是哪一个基类的呢?于是出现了二义性。但是在上例中解决了这个问题,其办法是通过作用域运算符::进行了限定。如果不加以限定,则会出现二义性问题。