#pragma twice

KAB-studio > プログラミング > #pragma twice > 337 Version 16.10 コンストラクタの復習

#pragma twice 337 Version 16.10 コンストラクタの復習

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

 Version 16.10
コンストラクタの復習

さて、今回はコンストラクタについて説明します
ちょっ、まっ!!

前回の、前回の!
…… const メンバ関数については、慣れやノウハウでなんとかするしか
ないかも。当分は const ポインタや const 参照は一部でしか使わないよう
にして、 const メンバ関数は getter 等の分かりやすいものにだけ付ける
とか
うわぁ消極的
いや実際、 const メンバ関数はきっと C++言語の中で一番難しいと思う

一番難しい……?
そ、実践で使うには仕様が複雑だし、単純なルールとか作るの難しいから
ね。だから、当面は深入りしない方がいいかも
でも、 const ポインタとか使えないのはちょっとね……
そうだね、作るのは深入りしなくても、 MFC の使用例を参考に、どうい
う風にすればいいのか実例を見ていけば、いつか
使えるようになる?
なるよきっと
それまでの辛抱ってことね
さて、今回はコンストラクタについて復習します
コンストラクタも何度か出てきたね
 Version 7.08 ( No.128 ) 、 Version 11.11 ( No.211 ) 、 
Version 11.17 ( No.217 ) 、 Version 11.18 ( No.218 ) で説明したね
よーするに、クラスの変数を作るときに呼ぶ関数なんだよね
そう。たとえばこんな感じ

// Data.h

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

public:
    // コンストラクタ。
    CData();

    // m_iData の getter 。
    int GetData() const;
};


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

#include "Data.h"

// コンストラクタ。
CData::CData()
{
    m_iData = 0;
}

// m_iData の getter 。
int CData::GetData() const
{
    return m_iData;
}

コンストラクタは、クラス名と同じ名前のメンバ関数です

    // コンストラクタ。
    CData();

戻り値がない点に注意してください
戻り値があっても受け取れないもんね
コンストラクタでは、主にメンバ変数の初期化を行います

// コンストラクタ。
CData::CData()
{
    m_iData = 0;
}

このように、メンバ変数に初期値をセットするのがコンストラクタの役割
です
あれ、もうひとつ別の書き方があるんじゃなかったっけ
そう。実は、この例は本当は間違い。メンバ変数をちゃんと初期化する場
合には、以下のようにします

// コンストラクタ。
CData::CData()
    : m_iData( 0 )
{
}

相変わらず見慣れない書き方……
メンバ変数の〈本当の初期化〉は、{の直前に行います。これはなぜ
かというと、〈処理の前に初期化が必要だから〉です
処理の前に初期化?
コンストラクタの {} の中では、計算とか、関数を呼んだりといったこと
ができてしまいます。メンバ変数の初期化は、そういったことの前にしてお
かないといけません
なるほど、初期化してない変数で計算しちゃまずいもんね
特に、メンバ変数が const の場合は、この方法でないと初期化できませ


    // private メンバ変数。
    const int m_iData;

const な変数は、変数を宣言したと同時に値をセットする、つまり初期化
時に値をセットしなければいけません
 {} の中に入っちゃったら、もう変数が作られちゃってるからそれじゃダメ
ってわけね
そういうこと。だから、 const 変数の場合にはこのように { の前で初期化
する必要がある、というわけです
 () で初期化するのは Version 11.18 ( No.218 ) で教わった方法だね
そう、変数は = だけじゃなく () で関数のように初期化できるんだけど、
このコンストラクタの初期化時には () で初期化しないとダメだから
なんで?
うーん、これはなんでだろう……うーん……
はいはい。じゃあ次
……使用例としては、こうなります

// 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;
    // GetData()メンバ関数を呼びだします。
    int i = cData.GetData();

    char pch[256];
    sprintf( pch, "%d\n", i );
    OutputDebugString( pch );
    // 0

    return 0;
}

コンストラクタは、変数を宣言したときに呼びだされます

    // CData クラスの変数を宣言します。
    // ここでコンストラクタが呼びだされます。
    CData cData;

この時にコンストラクタ、つまりCDataクラスのCDataメンバ関数が呼びだ
される、というわけです
質問!
はい火美ちゃん
 CData クラスに SetData() メンバ関数作って、外から初期化する、って
いうのはだめなの?
基本的にダメ。 Version 16.05 ( No.332 ) で【カプセル化】について説
明したでしょ
うん、メンバ変数を private にして、 getter と setter を作るってゆー
のだよね
そうそれ。カプセル化の考え方っていうのは〈自分のことは自分で面倒を
見る〉という考え方なんです
???
メンバ変数を private にして getter と setter を作ることで、クラス
の中を〈閉じた空間〉にすることができます
うん、メンバ関数経由でしかアクセスできないもんね
こうするのは、 CData クラスについて一番適切に処理できるのは CData 
クラス自身、だから実際にメンバ変数へとアクセスするのは自分だけ、だか
らです
うん
だから、自分自身の初期化も自分でするわけです。初期値は、もしかした
ら 0 じゃなく他の値の方がいいかもしれないし、そういったことを考えて
最も適切な初期化ができるのは自分自身だけだから
うーん、なんとなく分かるような……
分かりにくいのは、これが一種の〈思想〉だからなんだと思うよ
しそー?
考え方、クラスに……なんて言うのかな、人権?
クラス権?
そういうものを与える、っていう考え方なんだよね。たとえばクラスが 
DLL 単体で提供されていたら、プログラムは見えないでしょ
うん、見えないね
そのクラスは完全に閉じた存在、ブラックボックスになっていて public 
メンバ関数経由でしかアクセスできないわけだ
それがカプセル化……
中でなにやってるか分からないけど、それは気にしない、クラスの自主性
に任せる、っていうのがカプセル化の考え方
そのクラスのプログラムが間違っていたら?
使わない
む……
まぁ、そういう融通の利かない部分があるからこそ、クラスってとっつき
にくい所があると思うから、そういった部分をどう理解するかもこれからの
問題かも

/*
    Preview Next Story!
*/
なんかしそーとか言われると難しいかも
言語仕様の裏にある考え方を理解できるといいんだけど
そういうのって必要?
必須じゃないけどあるといいかな
んー
というわけで次回
< Version 16.11 様々なコンストラクタ >
につづく!
じゃあこう考えて、 C++言語を作った人の気持ちになる
なんかよけいわからん……
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。