コンスとラクタ 2 | ゲームプログラマ志望が福岡で叫ぶ 『絶望』

ゲームプログラマ志望が福岡で叫ぶ 『絶望』

プログラマーになりたい!!!!! あ、風のうわさで聞いた最近若者で流行っているトゥイッターなるものを始めてみました (・ト・) @toshi_desu_yo

前回書いたコンストラクタの第2章をふつふつを書いていく。



まずは 【explicit】

コンストラクタの前につけることでちょっと特殊にするキーワードです。



class A
{
private:
    int mNumber;

public:
    explicit A( int number  )
        : mNumber( number )
    { }
};



こいつを前につけることで暗黙の型変換ができなくなる。
お・恐ろしい・・((((;゚Д゚))))

暗黙的? 明示的??
どういうこと?



まず、explicit がついていないクラスAがあるとします。
そして、


void Func( A funcA ) { /** 何らかの処理 **/ }



という関数があった場合、


A testA( 1 );    // コンストラクタ
Func( testA );  // コピーコンストラクタが発生

これは前回の通り自動的に生成されたデフォルトコピーコンストラクタが呼ばれて
testA の メンバ変数 mNumber の値が funcA mNumber に無事コピーされます。


これは見た瞬間に正しいとわかりますね。
しかし、この関数の呼び出し方。別の書き方もできます。それが


Func( 20 );

これは通ります。

コンパイラが黙的に型の変換を行なってくれたからです。
自動的に int → A型に変換



『おお! 自動的にやってくれるなんて便利じゃないか!』
と、思われるかもしれませんが、、

(ノ∀`)アチャー

これはやってはいけないことです。


他の人がこのソースを見た時に、
恐らく、絶対、確実に、半端無く、絶望的に

『 Func という関数は引数に整数型をとるんだな!』と、いらぬ誤解を生みます。


そして作成したAさんも後から見なおした時に混乱するでしょう。
プログラムなんて3日経てば自分で書いたことなど忘れるものですたい( ゚д゚ )

さらに意図しない変換を起こしてしまい、最悪エラーが出てくるかもしれません。
そこに時間をかけるのは無駄。

ならば最初から暗黙的な型変換を出来ないようにすればいいやない! ということです。


なので、
ここで登場するのが 『 explicit 』 ちゃん!  明白な~ という意味らしい。
この子をコンストラクタの前、 につけることで、




Func( 20 );            // エラー!  暗黙的・・・
Func( A( 20 ) );     // 通る!  キャストをして明示的!!



特別な理由が無い限りは explicit を必ず書いといてもいいんじゃないかな!
これにより明示的(キャスト)に記述していない場合、ビルドした時点でエラーが分かります。
便利ですわね!


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

次に、コピーしたくないオブジェクトがある場合。
(コピーコンストラクタ、代入演算子を呼び出されたくない場合)


自分の複製を作りたくないと思っていても人間はやってしまうもの。

なので、コンパイラにこのクラスはコピーしないで!”と定義してあげると、万が一コピーが発生する場面でもエラーをはいてくれるので助かります。



A1 = A2;            // いや!
A A2( A1 );        // これもやめて!!


方法は、
ただコピーコンストラクタ、代入演算子を privateにしてやれば良い。

class A
{
public:
    /** 生成と破棄は通常通り~ **/
    A(){}
    ~A(){}

private:
    /** 呼び出されなようprivate宣言のみでおk) **/
    A( const A& );
    A& operator = ( const A& );
}:



関数の引数はいりません。
だって使わないから。
省略しよう!

これでもし自分が予期せぬコピーが発生しようともコンパイラが教えてくれます( ゚д゚ )


後、ちょっと便利なやり方として継承を使う手もあります

class UnCopy
{
protected:
    /** 生成は通常通り **/
    UnCopy(){}
    ~UnCopy(){}

private:
    /** コピーはダメ! **/
    UnCopy();
    UnCopy& operator=( const UnCopy& );
};

こういう中身が何もないクラスを作成したとします。
そして、これをコピーしたくないクラスに継承させます。


/** private 継承 **/
class A : private UnCopy
{
    /** コピーコンストラクタ、代入演算子を宣言不可 **/
};



これでどんなクラスでも、コピーコンストラクタと代入演算子を宣言することができなくなります。
コンパイラがデフォルト関数を自動的に作成する時に、親クラスの対応する関数を呼びだそうとするらしい。 でも、その対応する関数がprivateならばその呼出しがエラーとなる


様々な機能をクラスで作成し、多重継承を活用することで無駄なコードを省けスッキリとした見栄えをだし、匠もびっくりデス。
継承を使えるのならばどんどん使っていくといいんじゃないかなと。


【結論】

特別なことがない限り explicit をコンストラクタの前に付ける!
コピーしたくないならばprivateに!
継承を活用しよう!


お昼のうどん( ぶっかけ月見 )美味しかった!




何故か俺の中では explicit青色ってイメージがするんだよなぁ・・・ なんでだろう