#pragma twice

KAB-studio > プログラミング > #pragma twice > 339 Version 16.12 コピーコンストラクタを作る

#pragma twice 339 Version 16.12 コピーコンストラクタを作る

前のページへ 表紙・目次へ 次のページへ

 Version 16.12
コピーコンストラクタを作る

「今回は、前回説明したコピーコンストラクタの作り方について説明します」
『メンバ変数の中身をコピーしてくれるコンストラクタなんだよね』
「そうなんだけど、コピーコンストラクタを作ったら、そのコピーの処理は
自分で書かなきゃいけないんです」
『げ、それ面倒』
「だから、単にコピーするだけならコピーコンストラクタを作る必要はない
かな。コピー時に特別な処理が必要な時だけコピーコンストラクタを作る、
っていうのがいいかな」
『りょーかい』
「さて、では実際にコピーコンストラクタを作ってみます。まずクラスの
宣言の側」

// Data.h

// CDataクラス。
class CData
{
public:
    // private メンバ変数。
    int m_iData;

public:
    // 引数のないコンストラクタ。
    CData();

    // コピーコンストラクタ。
    CData( const CData &p_rcData );
};

『あれ? コピーコンストラクタって…… CData クラスの、const 参照な
んだ』

    // コピーコンストラクタ。
    CData( const CData &p_rcData );

「そう、これは仕様として決められているから変えられません。それに、前
回説明したように、以下のようにして渡せないといけないから」

    // もうひとつ CData クラスの変数を宣言します。
    // コピーコンストラクタでコピーします。
    CData cData2( cData );

『そか、普通に渡せなきゃいけないから自分のクラスの参照になるんだね。 
const なのは書き換え不可にするから?』
「そういうこと。コピー元が書き換わっちゃ意味ないからね。次に、この時
呼ばれるコピーコンストラクタの定義の方を見てみます」

// Data.cpp
#include <Windows.h>
#include <stdio.h>

#include "Data.h"

// 引数のないコンストラクタ。
CData:: CData()
    : m_iData( 0 )
{
}

// コピーコンストラクタ。
CData:: CData( const CData &p_rcData )
    : m_iData( p_rcData.m_iData )
{
    // テスト用に出力します。
    char pch[256];
    sprintf( pch, "CData::CData( const CData & ):%d\n", m_iData );
    OutputDebugString( pch );
}

「コピーコンストラクタは以下の部分」

// コピーコンストラクタ。
CData:: CData( const CData &p_rcData )
    : m_iData( p_rcData.m_iData )
{
    // テスト用に出力します。
    char pch[256];
    sprintf( pch, "CData::CData( const CData & ):%d\n", m_iData );
    OutputDebugString( pch );
}

「この関数の中身は、テスト用に出力している箇所だから本当は必要ないか
らね」
『ってことは、必要なのは』

CData:: CData( const CData &p_rcData )
    : m_iData( p_rcData.m_iData )
{
}

『ってことね。引数で自クラスの const 参照受け取って、メンバ変数の 
m_iData をコピー……あ、これがコピーしてるとこなんだ』
「そういうこと。これをしないと、コピーコンストラクタが呼ばれているの
にデータがコピーされていない、ってことになるから注意してね」
『はーい』
「あとは引数を持つコンストラクタと同じ。引数が自クラスの const 参照
っていうところだけが他のコンストラクタとの違いだね」
『そう考えると特に難しくないね……あ、質問!』
「はい火美ちゃん」
『引数のないコンストラクタってなんであるの? 省略してもいい?』
「ううん、前回説明したように引数を持つコンストラクタを省略すると」
『あ、デフォルトコンストラクタが消えちゃう!』
「だから、代わりに引数のないコンストラクタを作らなきゃいけないんで
す」
『それはコピーコンストラクタでも同じってことなのね……んー』
「どうしたの?」
『ううんなんでもない。で、使用例はどんな感じ』
「うん、使用例と出力結果は以下のようになります」

// Main.cpp
#include <Windows.h>
#include <stdio.h>

#include "Data.h"
int WINAPI WinMain
    ( HINSTANCE p_hInstance
    , HINSTANCE p_hPrevInstance
    , LPSTR p_pchCmdLine
    , int p_iCmdShow
    )
{
    // CData クラスの変数を宣言します。
    CData cData;
    cData.m_iData = 100;

    // もうひとつ CData クラスの変数を宣言します。
    // コピーコンストラクタでコピーします。
    CData cData2( cData );
    // CData::CData( const CData & ):100

    // 出力します。
    char pch[256];
    sprintf( pch, "%d\n", cData2.m_iData );
    OutputDebugString( pch );
    // 100
}

『コピーコンストラクタの使い方は、前回のと同じだね』

    // もうひとつ CData クラスの変数を宣言します。
    // コピーコンストラクタでコピーします。
    CData cData2( cData );
    // CData::CData( const CData & ):100

『ちゃんと作ったコンストラクタが呼ばれてるね』
「そこが重要。自動的に作られたコピーコンストラクタと同じように、作成
したコピーコンストラクタがちゃんと呼ばれてるってこと」
『…………』
「? どうしたの?」
『……質問!』
「はい火美ちゃん」
『今さ、その自動的に作られたコピーコンストラクタの代わりに呼ばれたっ
て言ったけど……それってさ、単に、自クラスの const 参照を引数に持つ
コンストラクタが呼ばれた、ってだけじゃないの?』
「あ、そう見えちゃうよね」
『見えちゃうっていうか、そうじゃないの? ってゆーか、もしかして
コピーコンストラクタっていうものが存在しないんじゃないの?』
「そんなことはないよ。たとえば、コピーコンストラクタは以下のようにし
て使うことができるんです」

    // もうひとつ CData クラスの変数を宣言します。
    // コピーコンストラクタでコピーします。
    CData cData2 = cData;
    // CData::CData( const CData & ):100

『…… = で渡してる?』
「引数を持つコンストラクタの時に説明したけど」
『あ! そういえば、あのとき = で、引数ひとつのコンストラクタを呼び
出せるって……』
「それと同じ。そのとき、自クラスを渡すとコピーコンストラクタが呼び出
されるんです」
『そして……この = の時も、ちゃんとコピーコンストラクタが呼び出され
てる!』
「そういうこと。まとめると以下のようになります」

・クラス型変数の初期化時に同じクラスの変数を渡すとコピーコンストラクタ
 が呼び出される。

・コピーコンストラクタは初めから存在する。

・「自クラスの const 参照」を引数に持つコンストラクタを作ると、それが
 コピーコンストラクタになる。

『ふ、複雑……』
「コピーコンストラクタっていう見えないコンストラクタがあって、それを
自クラスの const 参照で作ることができる、っていうところが難しいかも
ね。見えない所だし」
『見えないものは難しいよ……』

/*
    Preview Next Story!
*/
『……なんか、この前の const といい、難しくなってきたね……』
「でしょう」
『でしょう、じゃねー!!』
「でももっと難しくなるよ」
『うそー』
「でもその前に復習から」
『なんだ良かったー』
「というわけで次回」
< Version 16.13 オーバーロードの復習 >
『につづく!』
「ほら、甘いものの前に酸っぱいものをって」
『ダメじゃん!』
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。