c++中初始化列表的学习

来源:互联网 发布:apache框架 编辑:程序博客网 时间:2024/06/08 14:18

                                                     关于初始化成员变量的一个测试

今天看书的时候看到说是:如果我们有一个类成员,它本身是一个类或者是一个结构,而且这个成员它只有一个带参数的构造函数,而没有默认构造函数,这时要对这个类成员进行初始化,就必须调用这个类成员的带参数的构造函数,如果没有初始化列表,那么他将无法完成第一步,就会报错。

     刚开始不是很理解就按照书上的例子做啦一个测试,代码如下:(这个例子是用的初始化列表的形式初始化的。)

#include <QtCore/QCoreApplication>

#include <QDebug>

class Cpoint

{

public:

    int nPosX,nPosY;

public:

Cpoint(int x,int y)

 {

        nPosX = x;

        nPosY = y;

        qDebug() << "the Cpoint constructor called!/n" << endl ;

 }

 void ShowPos()

 {

      qDebug() << "the pos :x=" << nPosX << "y=" << nPosY << endl ;

 }

};

class CSize

{

public:

CSize(int l, int w)

 {

  nLength = l ;

  nWidth = w ;

  qDebug() << "the CSize constructor is called! " << endl ;

 }

 void ShowSize()

 {

    qDebug() << "the size : nLength=" << nLength << "nWidth=" << nWidth << endl ;

 }

public :

        int nLength ;

        int nWidth ;

};

class CRect

{

public :

        CRect(int left, int top ,int right ,int bottom):ptCenter((left+right)/2,

                                                                 (top+bottom)/2),size(right-left,bottom-top)

        {

            qDebug() <<  "the CRect constructor is called! " << endl ;

        }

    void Show()

    {

        ptCenter.ShowPos();

        size.ShowSize();

    }

private:

    Cpoint  ptCenter ;

    CSize  size ;

};

int main(int argc, char *argv[])

{

    QCoreApplication a(argc, argv);

    qDebug() <<  "I'm here to creat CRect !!" << endl ;

    CRect rc(10,100,80,250);

    rc.Show();

    return a.exec();

}

代码运行的结果如下:

这个照着书上抄的程序肯定是对的啦!

然后书上说只能以初始化列表的方式进行初始化,我就做啦 如下测试,故意不用初始化列表,看最后的结果怎么样,代码如下:

#include <QtCore/QCoreApplication>
#include <QDebug>
class Cpoint
{
public:
    int nPosX,nPosY;
public:
Cpoint(int x,int y)
 {
        nPosX = x;
        nPosY = y;
        qDebug() << "the Cpoint constructor called!/n" << endl ;
 }
 void ShowPos()
 {
      qDebug() << "the pos :x=" << nPosX << "y=" << nPosY << endl ;
 }
};
class CSize
{
public:
CSize(int l, int w)
 {
  nLength = l ;
  nWidth = w ;
  qDebug() << "the CSize constructor is called! " << endl ;
 }
 void ShowSize()
 {
    qDebug() << "the size : nLength=" << nLength << "nWidth=" << nWidth << endl ;
 }
public :
        int nLength ;
        int nWidth ;
};
class CRect
{
public :
#if 0
        CRect(int left, int top ,int right ,int bottom):ptCenter((left+right)/2,
                                                                 (top+bottom)/2),size(right-left,bottom-top)
        {
            qDebug() <<  "the CRect constructor is called! " << endl ;
        }
#endif
CRect(int left, int top ,int right ,int bottom)
{
                qDebug() <<  "I'm here to ptCenter !!" << endl ;
        ptCenter = Cpoint((left+right)/2,(top+bottom)/2) ;
                 qDebug() <<  "I'm here to size !!" << endl ;
        size = CSize(right-left,bottom-top) ;
}

 

    void Show()
    {
        ptCenter.ShowPos();
        size.ShowSize();
    }
private:
    Cpoint  ptCenter ;
    CSize  size ;
};
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    qDebug() <<  "I'm here to creat CRect !!" << endl ;
    CRect rc(10,100,80,250);
    rc.Show();
    return a.exec();
}

但是这样编译的时候真的如上所说的错误啦。错误如下:

错误的意思就是说没有找到默认的构造函数,因为要是我们自己重载啦构造函数,则默认构造函数消失,这样我试着加啦两个构造函数,如下:

Cpoint()

{

    qDebug() << "the Cpoint 222 constructor called!/n" << endl ;

 }

CSize()

 {

        qDebug() << "the CSize 222 constructor is called! " << endl ;

 }

呵呵,这两个构造函数长得跟默认构造函数很像,因为里面什么语句都没有加,这里再编译的时候,结果真的没有错误啦!呵呵!输出结果如下:

很显然结果跟上面的结果一样,就是说当我们自己重载了一个类似于默认构造函数的构造函数之后是可以的。咋一看貌似很明了,但是看到上面的构造函数不禁又有一个疑问?

CRect(int left, int top ,int right ,int bottom)
{
        qDebug() <<  "I'm here to ptCenter !!" << endl ;
        ptCenter = Cpoint((left+right)/2,(top+bottom)/2) ;
        qDebug() <<  "I'm here to size !!" << endl ;
        size = CSize(right-left,bottom-top) ;
}

这个构造函数中的两个等号难道不应该是要调用复制构造函数么???于是我又给这两个类分别加了一个复制构造函数!如下:

Cpoint( Cpoint  &cp)

{

    nPosX = cp.nPosX ;

    nPosY = cp.nPosY ;

    qDebug() << "the Cpoint  copy constructor called!/n" << endl ;

}

CSize( CSize  &cs)

 {

      nLength = cs.nLength ;

      nWidth = cs.nWidth ;

      qDebug() << "the CSize  copy constructor called!/n" << endl ;

 }

但是这样之后打印的结果还是如下:

意思就是说这两个复制构造函数没有被调用!郁闷啦半天!最后终于弄明白啦!在网上看到这段文字: 因为类类型的数据成员对象在进入函数体前已经构造完成,也就是说在成员初始化列表处进行构造对象的工作,调用构造函数,在进入函数体之后,进行的是对已经构造好的类对象的赋值,又调用个拷贝赋值操作符才能完成(如果并未提供,则使用编译器提供的默认按成员赋值行为)

这个上面说的很清楚,于是我在那个构造函数里又加啦两句打印,如下:

CRect(int left, int top ,int right ,int bottom)

{

        qDebug() << "the ptCenter " << ptCenter.nPosX << ptCenter.nPosY << endl ;

        qDebug() <<  "I'm here to ptCenter !!" << endl ;

        ptCenter = Cpoint((left+right)/2,(top+bottom)/2) ;

        qDebug() << "the size " << size.nLength << size.nWidth << endl ;

        qDebug() <<  "I'm here to size !!" << endl ;

        size = CSize(right-left,bottom-top) ;

}

也就是说按照上面所说的话,在进入构造函数的时候,这个ptCentersize

已经有值的!于是运行啦这个程序,结果如下:

这个刚说应证啦上面的猜测,呵呵!这下也就理解啦!为何用初始化列表的效率高!

再就是注意复制与赋值的区别,复制是用一个已经创建的对象(其实可以说已经初始化的)去创建一个对象,而赋值则是对一个已经创建的对象进行赋值操作改变其值!

为了测试我在主函数中加入如下语句,如下:

int main(int argc, char *argv[])

{

    QCoreApplication a(argc, argv);

Cpoint cp(30,40) ;

qDebug() <<  "I'm here to check the copy Cpoint constructor !!" << endl ;

    Cpoint testcp = cp ;

    testcp.ShowPos();

    qDebug() <<  "I'm here to creat CRect !!" << endl ;

    CRect rc(10,100,80,250);

    rc.Show();

    return a.exec();

}

运行的结果如下:

正如上面那里,复制构造函数被调用!这下算是没有疑问啦,呵呵!c++这个东西很难啃啊!记录一下,怕以后忘记啦!