一、派生类的构造函数
派生类不会继承基类的构造函数和析构函数,继承的基类成员的初始化要通过派生类的构造函数,析构要通过派生类的析构函数来实现。
执行派生类的构造函数的时候,应当使得派生类的数据成员和基类的数据成员都被初始化。
派生类名 (形式参数列表):基类名(基类构造函数实参列表),派生类的初始化列表
{
派生类初始化函数体
}
基类名(基类构造函数实参列表) 就是实现了调用基类的构造函数,派生类中新增加的成员可以在派生类的初始化列表 ,或者函数体内初始化。
class Point {
int x,y;
public:
Point(int a,int b):x(a),y(b) { } //构造函数
};
class Rect : public Point { int h,w;
public:
Rect(int a,int b,int c,int d):Point(a,b),h(c),w(d) { } //派生类构造函数
};
1.调用基类的构造函数 2.执行派生类初始化列表 3.执行派生类初始化函数体。
组合关系的派生类的构造函数:派生类A和B是组合关系,类A中有类B的子对象。
如果类B内有默认构造函数,或者具有全默认参数的构造函数,或者有无参数的构造函数,可以不用显式的调用B的构造函数进行初始化。
类名(形式参数列表) : 子对象名(子对象构造函数实参列表),类初始化列表
{
类初始化函数体
}
1.优先调用基类的构造函数
2.调用各个子对象的构造函数
3.执行派生类的初始化列表
4.执行初始化函数体
若基类和子对象所属的类中都没有定义带有参数的构造函数,同时自己也没有数据成员需要初始化,就可以不定义派生类的构造函数,执行的时候会按照相应的顺序调用各自的默认构造函数。
基类中没有含有参数的构造函数的时候,派生类可以不显式的调用基类的构造函数。
若子类和基类中含有带有参数的构造函数,则必须显式的调用构造二者的构造函数。
若构造函数重载后,可以显式调用,也可不显式调用。
二、派生类的析构函数
析构函数的调用顺序是:优先调用自己的析构函数,清理派生类的新增加成员,然后调用子对象的析构函数,最后调用基类的析构函数。
#include <iostream>
using namespace std;
class A{
public:
A(){cout<<"A constructor"<<endl;}
~A(){cout<<"A destructor"<<endl;}
};
class B: public A{
public:
B(){cout<<"B constructor"<<endl;}
~B(){cout<<"B destructor"<<endl;}
};
class C: public B{
public:
C(){cout<<"C constructor"<<endl;}
~C(){cout<<"C destructor"<<endl;}
}
声明一个c对象的时候,运行结果如下
A constructor
B constructor
C constructor
C destructor
B destructor
A destruc
#include <iostream>
#include<string>
using namespace std;
class Undergraduate{ //基类
protected: //保护部分
int num;
string name;
char sex ;
public: //公用部分
Undergraduate(int n,string nam,char s ) //基类构造函数
{ num=n; name=nam; sex=s; }
~Undergraduate(){} //基类析构函数
};
class graduate_stu: public Undergraduate{ //公用派生类
private: //派生类的私有部分
int age;
string addr;
public:
graduate_stu(int n,string nam,char s,int a,string ad ) :
Undergraduate(n,nam,s) //派生类构造函数
{ age=a; addr=ad;} //在函数体中只对派生类新增的数据成员初始化
void show( )
{ cout<<"num: "<<num<<"name: "<<name<<"sex: "<<sex<<"age: "<<age<<"address: "<<addr<<endl;}
~graduate_stu( ) { } //派生类析构函数
}
int main( )
{ graduate_stu stud1(10010,"Wang-li",'f',19,"115 Beijing Road,Shanghai");
graduate_stu stud2(10011,
"Zhang-fun",'m',21, "213 Shanghai Road,Beijing");
stud1.show( ); //输出第一个学生的数据
stud2.show( ); //输出第二个学生的数据
return 0;
}
三、多重继承派生类
多重继承的派生类的构造函数和单继承的一样,用逗号隔开基类的构造函数即可。
C++要求派生类对基类成员的继承必须没有二义性,多个基类之间不能有同名成员。但是可以通过自己的类体内的重写解决这一问题。
使用成员名的限定,解决二义性。
c.A::fun()
c.B::fun()
使用域运算符限定基类。
若外层声明了一个名字,而内层没有声明,则可见。若内层也声明了同名的新成员,对类而言外层的成员被覆盖。直接使用成员名智能访问本类中的派生类成员。
称为隐藏规则。
要是用作用域运算符才能访问同名成员。
覆盖掉之后不存在二义性。以类内为主。
四、虚基类
解决多重继承的二义性问题。
继承间接的共同基类时候只保留一个同名成员。
将该基类的所有派生继承中,全声明为虚基类,则该基类多次继承,重复继承后,也只会保留一个同名的成员。
class 派生类名: virtual 访问标号 虚基类名字,{
类体
};
虚基类的初始化,若定义了带参数的构造函数,派生类中都需要显式的调用构造函数对其进行初始化。
class A { public: A(int) {} }; //定义基类
class B : virtual public A { public: B(int a):A(a) {} };
//对基类A初始化
class C : virtual public A { public: C(int a):A(a) {} };
//对基类A初始化
class D : public B,public C
{ public: D(int a):A(a),B(a),C(a) {} };
尽管D的父类不是直接的A,但A是虚基类,也需要对C进行初始化。
1. 一个类既可以作为虚基类也可以用作非虚基类。
2.构造函数成员初始化列表需要显式的调用虚基类的构造函数,否则其必须有默认构造函数。
3.默认构造列表中,虚基类的构造函数要先于非虚基类的构造函数执行。
#include <iostream>
using namespace std;
enum Color {Red,Yellow,Green,White}; //颜色枚举类型
class Circle { //圆类Circle的定义
float radius;
public:
Circle(float r) { radius=r;
cout<<"Circle initialized!"<<endl;
}
~Circle() {
cout<<"Circle destroyed!"<<endl;
}
float Area() {
return 3.1415926*radius*radius;
}
};
class Table { //桌子类Table的定义
float height;
public:
Table(float h) {
height=h;
cout<<"Table initialized!"<<endl; }
~Table() { cout<<"Table destroyed!"<<endl; }
float Height() { return height; }
};
class RoundTable:public Table,public Circle {//圆桌类的定义
Color color;
public:
RoundTable(float h,float r,Color c);
int GetColor() { return color; }
~RoundTable() { cout<<"RoundTable destroyed!"<<endl; }
};
RoundTable::RoundTable(float h,float r,Color c):
Table(h),Circle(r)//圆桌构造函数的定义
{
color=c;
cout<<"RoundTable initialized!"<<endl;
}
int main()
{
RoundTable cir_table(15.0,2.0,Yellow);
cout<<"The table properties are:"<<endl;
cout<<"Height="<<cir_table.Height()<<endl;//调用Table类的成员函数
cout<<"Area="<<cir_table.Area()<<endl; //调用circle类的成员函数
cout<<"Color="<<cir_table.GetColor()<<endl; //调用RoundTable类的成员函数
return 0;
};