c++でリストを初期化する学習

35583 ワード

メンバー変数の初期化に関するテスト
今日本を読んでいると、クラスメンバーが1つある場合、それ自体がクラスまたは構造であり、このメンバーはパラメータ付きのコンストラクション関数が1つしかなく、デフォルトのコンストラクション関数がない場合、このクラスメンバーを初期化するには、このクラスメンバーのパラメータ付きコンストラクション関数を呼び出す必要があります.初期化リストがなければ、では、彼は最初のステップを完成できないので、間違いを報告します.
最初はよく理解していなかったので、本の例に従ってテストをしました.コードは以下の通りです.(この例は初期化リストの形式で初期化されています.)
#include
#include
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();
}

しかし、このようにコンパイルするときは本当に上記のような間違いがありました.エラーは次のとおりです.
誤った意味は、デフォルトのコンストラクション関数が見つからないということです.もし私たちがコンストラクション関数を再ロードしたら、デフォルトのコンストラクション関数が消えてしまうので、次のように2つのコンストラクション関数を追加してみました.
Cpoint()
{
    qDebug() << "the Cpoint 222 constructor called!/n"<< endl ;
 }
CSize()
 {
        qDebug() << "the CSize 222 constructor is called! "<< endl ;
 }
ほほほ、この2つのコンストラクション関数はデフォルトのコンストラクション関数に似ています.中には何の文も入っていないので、ここでコンパイルしたとき、結果は本当に間違いありませんでした.ほほほ!出力結果は次のとおりです.
結果は上記の結果と同じであることは明らかです.つまり、デフォルトの構造関数に似た構造関数を自分で再ロードした後でよいということです.一見明らかに見えるが、上の構造関数を見ると疑問が残る.
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) ;
}

このコンストラクション関数の2つの等号は、レプリケーションコンストラクション関数を呼び出すべきではありませんか??そこで私はまたこの2つのクラスにそれぞれ1つの複製構造関数を追加しました!次のようになります.
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 ;
 }
しかし、その後の印刷結果は以下の通りです.
つまり、この2つのレプリケーション構造関数は呼び出されていません!長いこと気がふさいでいた.最後にやっと分かった!クラスタイプのデータメンバーオブジェクトは、関数体に入る前に構築が完了しているため、メンバー初期化リストでオブジェクトを構築する作業を行い、コンストラクション関数を呼び出し、関数体に入った後、構築されたクラスオブジェクトへの付与を行うため、コピー割り当てオペレータを呼び出して完了します(指定されていない場合は、コンパイラで指定されたデフォルトのメンバー別割り当て動作を使用します).
これははっきり言っているので、私はその構造関数に2つの印刷を追加しました.以下のようにします.
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) ;
}
つまり上記のようにコンストラクション関数に入るときにこのptCenter,size
もう価値がある!このプログラムを実行すると、次のようになります.
これはちょうど上の推測を証明したと言って、ほほほ!これで納得!なぜ初期化リストを使うのが効率的なのか!
さらに、レプリケーションと割り当ての違いに注意してください.レプリケーションは、作成されたオブジェクト(実際には初期化されていると言えます)でオブジェクトを作成し、割り当ては、作成されたオブジェクトに対して割り当て操作を行い、その値を変更します.
主関数に次の文を追加します.次のようにします.
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++これはかじりにくいですね.記録して、後で忘れることを恐れます!