『Effective C+』ノート:Tips 01-Tips 04
Tip 01:C++は言語連邦
C:C++はCをベースとしており、この部分がベースのCであり、テンプレート(template)がなく、異常(exceptions)がなく、リロード(overloading)がない
Object-Optinted C+:すなわちC with Classは、オブジェクト部分に向いています.
Template C+:C++の汎用プログラミング
STL:templateライブラリ.
プログラミングルール:
1.Cの場合、CにはObjectの概念がないため、値伝達(pass-by-value)は参照伝達(pass-by-reference)よりも効率的である.
2.Object-oritented C++とTemplate C++の場合、構造関数と構造関数の存在によりpass-by-reference-to-constの方が良い
3.STLでは、反復器と関数オブジェクトがCポインタ上に構築されているため、旧式のC pass-by-valueが再適用される
Tips 02:できるだけconst,enum,inlineで#defineの代わりにする
一、原因一:defineが使用する名前が記号テーブル(symbol table)に入らない可能性があり、デバッグが困難になる.
二、enum hackの使い方.
一部の古いコンパイラでは、staticメンバーが宣言式で初期値を取得できない場合があります.もちろん、初期値は定義式に置くことができます.
ただし、classコンパイルにはclass定数が必要です.のように
コンパイラがstatic const int NumTurns=5を通過しない場合.enum hackが必要です.
補足してstaticメンバー変数を初期化します.ヘッダファイル、クラス定義でstatic変数を宣言する
次に、ソースファイル(.cpp)でstatic変数を定義します.
三、#define定義の関数マクロは、inline+tepmlateで置き換えることが望ましい
aの増加回数は誰と比較するかによって決まる.
①++a,b.++a=6,a>b,戻り(++a),a=7;
②++a,b+10.++a=6,a,戻り(b),a=6
Tip 03:できるだけconstを使う
一、メンバー関数はconstの意味で、Class::Function()const.
1.bitwise constness:メンバー関数はメンバー変数を変更できません.つまり、オブジェクトのbitを変更できません.
ただし、メンバー変数がオブジェクトを指すポインタである場合、bitwiseの観点から、メンバー関数はポインタを変更することはできません.このメンバー関数内でポインタはポインタ定数に相当します.ただし、constメンバー関数では、ポインタが指すオブジェクトを変更できます.
しかしconstメンバー関数の初志は,ポインタが指すオブジェクトの変更を防止することである.
PS:コンパイラはbitwise constness
2.logical constness:constメンバー関数はメンバー変数を変更できますが、コンパイラが通過した場合のみです.
メンバー関数がconstである以上、コンパイラではメンバー関数を変更することはできません.コンパイラでチェックできるようにするにはどうすればいいですか.メンバー変数に修飾子mutableを追加すると、メンバー変数のbitwise constness制約を解放できます.すなわちconstメンバー関数内でもmutableメンバー変数を変更することができる.
二、non-constバージョンはconstバージョンを呼び出します.
通常constバージョンのnon-constの関数実装は同じであり、唯一の違いは戻りタイプである.この場合、non-constバージョンでconstバージョンを呼び出すことができます.
①(* this)をconstタイプstatic_に変換cast(*this).これでconstバージョンの関数を呼び出すことができます
②constバージョンの戻り値(const T&)をnon-constに変換します.
三、なぜnon-constバージョンがconstバージョンを呼び出せないのか
constメンバー関数はオブジェクトの論理状態(logical state)を絶対に変更しませんが、non-constメンバー関数にはこの制限はありません.constバージョンがnon-constバージョンを呼び出すと、const関数内でオブジェクトの論理状態が変更され、実際に変更されているかどうかにかかわらず、non-constバージョンに依存します.
Tip 04:オブジェクトが使用される前に初期化されることを決定する
一、賦値(assignment)と初期化(initialization)の違い
これを賦値と言います.Javaには初期化リストが存在しないため,この初期化方式しか採用できないため,Javaの初期化にはC++の付与が対応する.
二、初期化の順序
クラスのメンバー変数は、常に宣言された方法で初期化されます.すなわちクラスで宣言される順序がA,B,C,D…であっても、初期化リストの順序がB(xxx),D(xxx),C(xxx),A(xxx)であっても、実際の初期化順序はA,B,C,Dである
三、non-local staticオブジェクトとは何か.
一般的に関数内部に宣言される変数は、ローカル変数またはローカル変数と呼ばれます.したがってnon-local staticオブジェクトは,関数体の外で宣言されたstaticオブジェクトである.
四、non-local staticオブジェクトの初期化順序.
異なるコンパイルユニット内のnon-local staticオブジェクトの初期化順序を根本的に定義していない.
五、他のクラスがnon-local staticオブジェクトを使用しているが、そのオブジェクトが初期化されているかどうかを判断できない場合は、どのように解決しますか.
non-local staticオブジェクトをlocal staticオブジェクトに置き換えます.C++は、関数内のlocal staticオブジェクトが「この関数が呼び出されている間」「オブジェクトの定義式に初めて遭遇したとき」に初期化されることを保証します.non-local staticオブジェクトを関数呼び出し(referenceがlocal staticオブジェクトを指す)で置き換えると、初期化されたオブジェクトを指すに違いありません.
C:C++はCをベースとしており、この部分がベースのCであり、テンプレート(template)がなく、異常(exceptions)がなく、リロード(overloading)がない
Object-Optinted C+:すなわちC with Classは、オブジェクト部分に向いています.
Template C+:C++の汎用プログラミング
STL:templateライブラリ.
プログラミングルール:
1.Cの場合、CにはObjectの概念がないため、値伝達(pass-by-value)は参照伝達(pass-by-reference)よりも効率的である.
2.Object-oritented C++とTemplate C++の場合、構造関数と構造関数の存在によりpass-by-reference-to-constの方が良い
3.STLでは、反復器と関数オブジェクトがCポインタ上に構築されているため、旧式のC pass-by-valueが再適用される
Tips 02:できるだけconst,enum,inlineで#defineの代わりにする
一、原因一:defineが使用する名前が記号テーブル(symbol table)に入らない可能性があり、デバッグが困難になる.
二、enum hackの使い方.
一部の古いコンパイラでは、staticメンバーが宣言式で初期値を取得できない場合があります.もちろん、初期値は定義式に置くことができます.
ただし、classコンパイルにはclass定数が必要です.のように
class GamePlayer{
private:
static const int NumTurns = 5;
int scores[NumTurns];
}
コンパイラがstatic const int NumTurns=5を通過しない場合.enum hackが必要です.
class GamePlayer{
private:
enum {NumTurns = 5};
int scores[NumTurns];
}
補足してstaticメンバー変数を初期化します.ヘッダファイル、クラス定義でstatic変数を宣言する
static T sMember
次に、ソースファイル(.cpp)でstatic変数を定義します.
T Class::sMember = value
三、#define定義の関数マクロは、inline+tepmlateで置き換えることが望ましい
#define CALL_WITH_MAX f((a) > (b) > (a) : (b))
int a = 5 , b = 0;
CALL_WITH_MAX(++a, b) a = 7;
CALL_WITH_MAX(++a, b+10) a = 6;
aの増加回数は誰と比較するかによって決まる.
①++a,b.++a=6,a>b,戻り(++a),a=7;
②++a,b+10.++a=6,a,戻り(b),a=6
Tip 03:できるだけconstを使う
一、メンバー関数はconstの意味で、Class::Function()const.
1.bitwise constness:メンバー関数はメンバー変数を変更できません.つまり、オブジェクトのbitを変更できません.
ただし、メンバー変数がオブジェクトを指すポインタである場合、bitwiseの観点から、メンバー関数はポインタを変更することはできません.このメンバー関数内でポインタはポインタ定数に相当します.ただし、constメンバー関数では、ポインタが指すオブジェクトを変更できます.
しかしconstメンバー関数の初志は,ポインタが指すオブジェクトの変更を防止することである.
PS:コンパイラはbitwise constness
2.logical constness:constメンバー関数はメンバー変数を変更できますが、コンパイラが通過した場合のみです.
メンバー関数がconstである以上、コンパイラではメンバー関数を変更することはできません.コンパイラでチェックできるようにするにはどうすればいいですか.メンバー変数に修飾子mutableを追加すると、メンバー変数のbitwise constness制約を解放できます.すなわちconstメンバー関数内でもmutableメンバー変数を変更することができる.
二、non-constバージョンはconstバージョンを呼び出します.
通常constバージョンのnon-constの関数実装は同じであり、唯一の違いは戻りタイプである.この場合、non-constバージョンでconstバージョンを呼び出すことができます.
①(* this)をconstタイプstatic_に変換cast(*this).これでconstバージョンの関数を呼び出すことができます
static_cast(*this).function()
②constバージョンの戻り値(const T&)をnon-constに変換します.
const_cast( static_cast(*this).function())//(*this) reference of T
三、なぜnon-constバージョンがconstバージョンを呼び出せないのか
constメンバー関数はオブジェクトの論理状態(logical state)を絶対に変更しませんが、non-constメンバー関数にはこの制限はありません.constバージョンがnon-constバージョンを呼び出すと、const関数内でオブジェクトの論理状態が変更され、実際に変更されているかどうかにかかわらず、non-constバージョンに依存します.
Tip 04:オブジェクトが使用される前に初期化されることを決定する
一、賦値(assignment)と初期化(initialization)の違い
XXX::XXX(){
Member1 = xxx;
Member2 = xxx;
}
これを賦値と言います.Javaには初期化リストが存在しないため,この初期化方式しか採用できないため,Javaの初期化にはC++の付与が対応する.
二、初期化の順序
クラスのメンバー変数は、常に宣言された方法で初期化されます.すなわちクラスで宣言される順序がA,B,C,D…であっても、初期化リストの順序がB(xxx),D(xxx),C(xxx),A(xxx)であっても、実際の初期化順序はA,B,C,Dである
三、non-local staticオブジェクトとは何か.
一般的に関数内部に宣言される変数は、ローカル変数またはローカル変数と呼ばれます.したがってnon-local staticオブジェクトは,関数体の外で宣言されたstaticオブジェクトである.
四、non-local staticオブジェクトの初期化順序.
異なるコンパイルユニット内のnon-local staticオブジェクトの初期化順序を根本的に定義していない.
五、他のクラスがnon-local staticオブジェクトを使用しているが、そのオブジェクトが初期化されているかどうかを判断できない場合は、どのように解決しますか.
non-local staticオブジェクトをlocal staticオブジェクトに置き換えます.C++は、関数内のlocal staticオブジェクトが「この関数が呼び出されている間」「オブジェクトの定義式に初めて遭遇したとき」に初期化されることを保証します.non-local staticオブジェクトを関数呼び出し(referenceがlocal staticオブジェクトを指す)で置き換えると、初期化されたオブジェクトを指すに違いありません.