随笔 - 56, 文章 - 0, 评论 - 0, 引用 - 0
数据加载中……

派生类的构造函数及其对象的初始化

◆由于构造函数不能被继承,因此,派生类的构造函数中除了对派生类中数据成员进行初始化外,还必须通过调用直接基类的构造函数来对基类中数据成员初始化,一般地将,对派生类中数据成员初始化放在该派生类构造函数的函数体内,而调用基类构造函数的基类中数据成员初始化放在该构造函数的成员初始化表中。派生类构造函数的格式如下表示:
<派生类构造函数名>(<参数表>) : <成员初始化表>
{
  <派生类构造函数的函数体>
}
其中,<派生类构造函数名>同该派生类的类名。<成员初始化表>中包含如下的初始化项:
①基类的构造函数,用来给基类中数据成员初始化;
②子对象的类的构造函数,用来给派生类中子对象的数据成员初始化;
③派生类中常成员的初始化。
<派生类构造函数的函数体>用来给派生类中的数据成员初始化。
派生类构造函数的调用顺序如下:
①基类构造函数;
②子对象的构造函数;
③成员初始化表中其他初始化项;
④派生类构造函数的函数体。
在基类中有默认构造函数时,派生类的构造函数中可隐含调用基类中的默认构造函数。

派生类中析构函数
由于析构函数也不能继承,因此派生类的析构函数中将调用直接基类的析构函数。执行派生类析构函数的顺序正好与指向派生类的构造函数的顺序相反。先调用派生类的析构函数,再调用子对象类的析构函数,最后调用直接基类的析构函数。

例如:分析下列程序的输出结果,掌握派生类构造函数的定义格式和执行顺序,以及派生类析构函数的调用方法。

 1#include<iostream>
 2using namespace std;
 3class A
 4{
 5public:
 6    A()
 7    {
 8         a=0;
 9         cout<<"Default constructor called. A\n";
10    }
11    A(int i)
12    {
13        a=i;
14        cout<<"Constructor called. A\n";
15    }
16    ~A()
17    {
18        cout<<"Destructor called. A\n";
19    }
20    void Print()
21    {
22        cout<<a<<",";
23    }
24    int Geta()
25    {
26        return a;
27    }
28private:
29    int a;
30};
31class B:public A
32{
33public:
34    B()
35    {
36        b=0;
37        cout<<"Default constructor called. B\n";
38    }
39    B(int i,int j,int k);
40    ~B()
41    {
42        cout<<"Destructor called. B\n";
43    }
44    void Print()
45    {
46        A::Print();
47        cout<<b<<","<<aa.Geta()<<endl;
48    }
49private:
50    int b;
51    A aa;
52};
53
54B::B(int i,int j,int k):A(i),aa(j),b(k)
55{
56    cout<<"Constructor called. B\n";
57}
58int main()
59{
60    B bb[2];
61    bb[0]=B(8,3,9);
62    bb[1]=B(17,-18,19);
63    int i;
64    for(i=0;i<2;i++)
65        bb[i].Print();
66    return 0;
67}
68

运行结果为:
Default constructor called A.
Default constructor called A.
Default constructor called B.
Default constructor called A.
Default constructor called A.
Default constructor called B.
Constructor called. A
Constructor called. A
Constructor called. B
Destructor called. B
Destructor called. A
Destructor called. A
Constructor called. A
Constructor called. A
Constructor called. B
Destructor called. B
Destructor called. A
Destructor called. A
8,9,3
17,19,-18
Destructor called. B
Destructor called. A
Destructor called. A
Destructor called. B
Destructor called. A
Destructor called. A
分析:

派生类B的构造函数定义如下:
B( int i, int j, int k):A(i),aa(j),b(k)
{....}

该构造函数的成员初始表有3项:A(i)是调用直接基类的一个参数的构造函数给基类数据成员初始化;aa(j)是调用子对象的构造函数给子对象数据成员初始化;b(k)是对派生类本事的数据成员b初始化,该项可放在函数体内。
主函数中先创建一个B类的数组bb,它有两个元素,每个元素创建时调用一次B类的默认构造函数,该构造函数隐含调用基类默认构造函数,子对象类默认构造函数和自身函数体,因此,显示3条信息。
程序中的两条给数组元素bb[0]和bb[1]赋值的语句,共显示出12行信息。因为每调用一次派生类中带有3个参数的构造函数,则要显示输出3行信息,创建一个临时对象,完成了赋值任务后,要将临时对象释放掉,调用一次派生类B的析构函数,又要产生3行信息,注意其顺序与调用构造函数时所显示的3行信息顺序相反。
程序最后显示的6行信息是程序结束前将对象数组bb的两个元素释放掉所产生的。



读程序
#include<iostream>
using namespace std;

class Base1
{
    
int d1;
    
public:
    Base1(
int i)
    
{
        d1
=i;
        cout
<<"constructing Base1 "<<d1<<endl;
    }

}
;
class Base2
{
    
int d2;
    
public:
    Base2(
int j)
    
{
        d2
=j;
        cout
<<"constructing Base2 "<<d2<<endl;
    }

}
;
class Base3
{
    
int d3;
    
public:
    Base3(
int k=0)
    
{
        d3
=k;
        cout
<<"constructing Base3 "<<d3<<endl;
    }

}
;
class Derived:public Base3,public Base1,public Base2
{
    
int d4;
    Base1 memberObj1;
    Base3 memberObj3;
    Base2 memberObj2;
    
public:
    Derived(
int a,int b,int c,int d,int e)
           :memberObj2(d),memberObj3(b),memberObj1(c),Base2(a),Base1(b)
    
{
        d4
=e;
        cout
<<"constructing Derived "<<d4<<endl;
    }

}
;
int main()
{
    Derived obj(
1,2,3,4,5);
    
return 0;
}


结果显示:
constructing Base3 0
constructing Base1 2
constructing Base2 1
constructing Base1 3
constructing Base3 2
constructing Base2 4
constructing Derived 5

posted on 2009-08-21 11:22 八路 阅读(1147) 评论(0)  编辑 收藏 引用 所属分类: C++ 类


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理