c++閉鎖クラス
3944 ワード
1つのクラスのメンバー変数が別のクラスのオブジェクトである場合は、「メンバーオブジェクト」と呼ばれます.メンバー・オブジェクトを含むクラスを閉じたクラス(enclosed class)と呼びます.
クラス構造関数の初期化リストを閉じる
閉じたクラスのオブジェクトが生成されて初期化されると、含まれるメンバーオブジェクトも初期化される必要があります.これにより、メンバーオブジェクト構築関数の呼び出しが発生します.メンバーオブジェクトがどのコンストラクション関数で初期化されたのか、コンパイラに知らせるにはどうすればいいですか.これは、閉じたクラスのコンストラクション関数を定義するときに、初期化リストを追加することによって解決できます.コンストラクション関数に初期化リストを追加する方法は、次のとおりです.
クラス名::コンストラクション関数名(パラメータテーブル):メンバー変数1(パラメータテーブル)、メンバー変数2(パラメータテーブル)...{ ... } #include using namespace std; class CTyre//タイヤ類 { private: int radius;//半径 int width;//幅 public: CTyre(int r, int w) : radius(r), width(w) { } }; class CEngine//エンジンクラス { }; class CCar{//自動車類 private: int price;//価格 CTyre tyre; CEngine engine; public: CCar(int p, int tr, int tw); }; CCar::CCar(int p, int tr, int tw) : price(p), tyre(tr, tw) { }; int main() { CCar car(20000, 17, 225); return 0; }
9行目のコンストラクション関数に初期化リストが追加され、radiusをr、widthをwに初期化します.この書き方は,関数内でrとwを用いてradiusとwidthを付与するスタイルよりもよい.メンバー変数の初期化には、この書き方を使用することをお勧めします.CCarは閉じたクラスで、tyreとengineの2つのメンバーオブジェクトがあります.27行目をコンパイルする場合、コンパイラはcarオブジェクトのtyreとengineメンバーオブジェクトがどのように初期化されるかを知る必要があります.ここでcarオブジェクトが上のCCar(int p,int tr,int tw)コンストラクタで初期化されていることを評価器は知っているが,tyreとengineがどのように初期化されるかは,22行目のCCar(int p,int tr,int tw)の後ろの初期化リストを見る.この初期化リストは、tyreがtrとtwをパラメータとしてCTyre(intr,hit w)構造関数の初期化を呼び出すべきであることを示しているが、engineがどのように処理するかは説明されていない.この場合、コンパイラはengineをCEngineクラスの無パラメトリック構造関数で初期化すべきだと考えています.一方、CEngineクラスには、コンパイラが自動的に生成するデフォルトの無パラメトリック構造関数があるため、carオブジェクト全体の初期化問題が解決されます.要するに、閉じたクラスオブジェクトを生成する文は、コンパイラがメンバーオブジェクトがどのように初期化されているかを理解できるようにする必要があります.そうしないと、コンパイルエラーが発生します.上記のプログラムでは、CCarクラスのコンストラクション関数に初期化リストがない場合、コンパイラがcarをどのように初期化すべきか分からないため、27行目のコンパイルエラーが発生する.CTyreクラスにはパラメトリック関数がないため、コンパイラはcarを初期化するためのオブジェクトが見つからない.tyreオブジェクトのパラメータ.クラスオブジェクトを閉じて生成する場合は、すべてのメンバーオブジェクトのコンストラクション関数を実行してから、クラス独自のコンストラクション関数を閉じます.メンバー・オブジェクトのコンストラクション関数の実行順序は、コンストラクション関数の初期化リストに表示される順序に関係なく、クラス定義におけるメンバー・オブジェクトの順序と一致します.閉じたクラスオブジェクトが消滅した場合、閉じたクラスの構造関数を実行してから、メンバーオブジェクトの構造関数を実行します.メンバーオブジェクトの構造関数の実行順序と構造関数の実行順序は逆です.つまり、先に構築された構造の構造は、C++がこのような順序の問題を処理する一般的な法則です.たとえば、次のプログラムがあります. #include using namespace std; class CTyre { public: CTyre() { cout << "CTyre constructor"<< endl; } ~CTyre() { cout << "CTyre destructor"<< endl; } }; class CEngine { public: CEngine() { cout << "CEngine constructor"<< endl; } ~CEngine() { cout << "CEngine destructor"<< endl; } }; class CCar { private: CEngine engine; CTyre tyre; public: CCar() { cout << "CCar constructor"<< endl; } ~CCar() { cout << "CCar destructor"<< endl; } }; int main() { CCar car; return 0; }
実行結果:CEngine constructor CTyre constructor CCar constructor CCar destructor CTyre destructor CEngine destructor閉じたクラスのオブジェクトを初期化する場合は、閉じたクラスのコンストラクション関数でメンバーオブジェクトが使用される可能性があるため、メンバーオブジェクトのコンストラクション関数を先に実行します.この時点でメンバーオブジェクトが初期化されていない場合は、合理的ではありません.思考問題:なぜクラスオブジェクトを閉じるときに、閉じたクラスの構造関数を実行してからメンバーオブジェクトの構造関数を実行するのか.
クラス構造関数の初期化リストを閉じる
閉じたクラスのオブジェクトが生成されて初期化されると、含まれるメンバーオブジェクトも初期化される必要があります.これにより、メンバーオブジェクト構築関数の呼び出しが発生します.メンバーオブジェクトがどのコンストラクション関数で初期化されたのか、コンパイラに知らせるにはどうすればいいですか.これは、閉じたクラスのコンストラクション関数を定義するときに、初期化リストを追加することによって解決できます.コンストラクション関数に初期化リストを追加する方法は、次のとおりです.
クラス名::コンストラクション関数名(パラメータテーブル):メンバー変数1(パラメータテーブル)、メンバー変数2(パラメータテーブル)...{ ... }
:
と{
の間の部分が初期化リストです.初期化リストのメンバー変数は、メンバーオブジェクトであっても、基本タイプのメンバー変数であってもよい.メンバー・オブジェクトの場合、初期化リストのパラメータ・テーブルには、コンストラクション関数のパラメータが格納されます(メンバー・オブジェクトがどのように初期化されるかを示します).基本タイプのメンバー変数の場合、パラメータテーブルには初期値が表示されます.「パラメータテーブル」のパラメータは、式の識別子が定義されている限り、変数や関数呼び出しなど、任意の定義された式であってもよい.例:
9行目のコンストラクション関数に初期化リストが追加され、radiusをr、widthをwに初期化します.この書き方は,関数内でrとwを用いてradiusとwidthを付与するスタイルよりもよい.メンバー変数の初期化には、この書き方を使用することをお勧めします.CCarは閉じたクラスで、tyreとengineの2つのメンバーオブジェクトがあります.27行目をコンパイルする場合、コンパイラはcarオブジェクトのtyreとengineメンバーオブジェクトがどのように初期化されるかを知る必要があります.ここでcarオブジェクトが上のCCar(int p,int tr,int tw)コンストラクタで初期化されていることを評価器は知っているが,tyreとengineがどのように初期化されるかは,22行目のCCar(int p,int tr,int tw)の後ろの初期化リストを見る.この初期化リストは、tyreがtrとtwをパラメータとしてCTyre(intr,hit w)構造関数の初期化を呼び出すべきであることを示しているが、engineがどのように処理するかは説明されていない.この場合、コンパイラはengineをCEngineクラスの無パラメトリック構造関数で初期化すべきだと考えています.一方、CEngineクラスには、コンパイラが自動的に生成するデフォルトの無パラメトリック構造関数があるため、carオブジェクト全体の初期化問題が解決されます.要するに、閉じたクラスオブジェクトを生成する文は、コンパイラがメンバーオブジェクトがどのように初期化されているかを理解できるようにする必要があります.そうしないと、コンパイルエラーが発生します.上記のプログラムでは、CCarクラスのコンストラクション関数に初期化リストがない場合、コンパイラがcarをどのように初期化すべきか分からないため、27行目のコンパイルエラーが発生する.CTyreクラスにはパラメトリック関数がないため、コンパイラはcarを初期化するためのオブジェクトが見つからない.tyreオブジェクトのパラメータ.クラスオブジェクトを閉じて生成する場合は、すべてのメンバーオブジェクトのコンストラクション関数を実行してから、クラス独自のコンストラクション関数を閉じます.メンバー・オブジェクトのコンストラクション関数の実行順序は、コンストラクション関数の初期化リストに表示される順序に関係なく、クラス定義におけるメンバー・オブジェクトの順序と一致します.閉じたクラスオブジェクトが消滅した場合、閉じたクラスの構造関数を実行してから、メンバーオブジェクトの構造関数を実行します.メンバーオブジェクトの構造関数の実行順序と構造関数の実行順序は逆です.つまり、先に構築された構造の構造は、C++がこのような順序の問題を処理する一般的な法則です.たとえば、次のプログラムがあります.
実行結果:CEngine constructor CTyre constructor CCar constructor CCar destructor CTyre destructor CEngine destructor閉じたクラスのオブジェクトを初期化する場合は、閉じたクラスのコンストラクション関数でメンバーオブジェクトが使用される可能性があるため、メンバーオブジェクトのコンストラクション関数を先に実行します.この時点でメンバーオブジェクトが初期化されていない場合は、合理的ではありません.思考問題:なぜクラスオブジェクトを閉じるときに、閉じたクラスの構造関数を実行してからメンバーオブジェクトの構造関数を実行するのか.