C++速成笔记(九)

本文详细解释了派生类构造函数的执行过程,包括调用基类构造函数、初始化列表和派生类初始化函数体。还介绍了析构函数的调用顺序,以及多重继承中虚基类的作用,解决了二义性问题。通过实例展示了如何在类定义中正确运用这些概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、派生类的构造函数

派生类不会继承基类的构造函数和析构函数,继承的基类成员的初始化要通过派生类的构造函数,析构要通过派生类的析构函数来实现。

执行派生类的构造函数的时候,应当使得派生类的数据成员和基类的数据成员都被初始化。

派生类名 (形式参数列表):基类名(基类构造函数实参列表),派生类的初始化列表
{
    派生类初始化函数体
}

基类名(基类构造函数实参列表)  就是实现了调用基类的构造函数,派生类中新增加的成员可以在派生类的初始化列表 ,或者函数体内初始化。

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;
};

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值