構造関数とthis呼び出しについて考える
3751 ワード
本文の一連の思考と内容は、あるクラスのコンストラクション関数で別のオブジェクトのコンストラクション関数を呼び出し、thisを使用して参照メンバーを初期化する必要があるという問題から生じています.
主な問題:
1.コンストラクション関数の初期化リストでthisにアクセスできますか?
c++がオブジェクトを作成するには、メモリの作成とコンストラクション関数の呼び出しの2つの部分に分かれていることは明らかです.初期化リストでは、現在のオブジェクトが消費するメモリが作成されていることは明らかです.ok、thisはアクセスできますが、一部のメンバーは初期化されていません(コンストラクション関数がまだ実行されていないため、オブジェクトが一部有効としか言えません).
コンストラクション関数の関数体でthisを使用すると完全に信頼性が高く、すべてのコンパイラが自動的に初期化できるメンバーが初期化を完了します(ベースクラスのメンバー、デフォルトのコンストラクション関数を持つメンバーなど、具体的な初期化順序はクラスメンバー定義順序によって決定されることに注意してください).ただし、現在のクラスの部分は初期化リストで初期化されておらず、デフォルトのコンストラクション関数クラスメンバー変数(一般的なc++組み込みタイプ、int、float、ポインタなど)の値は定義されていません.
2.コンストラクション関数パラメータはメンバーと同じ名前です.
コンストラクション関数の形式は、クラスメンバーと同じ名前のパラメータを持つものです.印刷出力は、メンバー変数が初期化されているかどうかを確認するためだけです.
初期化リストにthisが直接表示されないため、コンパイラはこのような重名の場合を処理します.すなわち、コンストラクション関数の初期化リストでthisを明示的に限定子にすることはできません.たとえば、次のコードはコンパイルできません.
3.あるクラスのコンストラクタ・アセンブリで別のコンストラクタを呼び出す方法
コンストラクション関数ではネストされた呼び出しは許可されませんが、異なるリロード形式を呼び出すことができます.例えば、次のコードです.(面接のテーマであることに注意してください)
出力はいくらですか?
---------------------------------------------------------------------------
答えは未知だm_iは初期化されていない変数であり、野値である.
"CLS(0);"の文は、一時的なCLSオブジェクトを作成し、そのオブジェクトのメンバーm_を表す.iは0に初期化されます.現在のオブジェクトの値は初期化されていません.
コンストラクション関数クラスが別のコンストラクション関数を呼び出す必要がある場合はplacement new演算子を使用する必要があります.コードは次のとおりです.
placement newについて知らない場合は、c++primerまたはTCPLを見ることをお勧めします.
c++11では、上記の機能は、構造関数を委任または継承する形で直接実現することができる.
4.ソリューション
ここまで書きます.コンストラクション関数の初期化リストでthisを参照する場合の基本的な理解では、本明細書で最初に提案した問題を次のコードで解決できます.
次の質問を繰り返します.あるクラスのコンストラクション関数で別のオブジェクトのコンストラクション関数を呼び出し、thisを使用して参照メンバーを初期化する必要があります.
クラスContextは、そのコンストラクション関数の初期化リストでthisによってRefのコンストラクション関数を呼び出します.
5.参考資料
[1]一つの問題からC++におけるコンストラクタ呼び出しコンストラクタhttp://www.cnblogs.com/chio/archive/2007/10/20/931043.html
[2]c++1つのコンストラクタが別のコンストラクタを呼び出すhttp://www.cnblogs.com/ayanmw/archive/2012/08/20/2647808.html
主な問題:
1.コンストラクション関数の初期化リストでthisにアクセスできますか?
c++がオブジェクトを作成するには、メモリの作成とコンストラクション関数の呼び出しの2つの部分に分かれていることは明らかです.初期化リストでは、現在のオブジェクトが消費するメモリが作成されていることは明らかです.ok、thisはアクセスできますが、一部のメンバーは初期化されていません(コンストラクション関数がまだ実行されていないため、オブジェクトが一部有効としか言えません).
コンストラクション関数の関数体でthisを使用すると完全に信頼性が高く、すべてのコンパイラが自動的に初期化できるメンバーが初期化を完了します(ベースクラスのメンバー、デフォルトのコンストラクション関数を持つメンバーなど、具体的な初期化順序はクラスメンバー定義順序によって決定されることに注意してください).ただし、現在のクラスの部分は初期化リストで初期化されておらず、デフォルトのコンストラクション関数クラスメンバー変数(一般的なc++組み込みタイプ、int、float、ポインタなど)の値は定義されていません.
2.コンストラクション関数パラメータはメンバーと同じ名前です.
コンストラクション関数の形式は、クラスメンバーと同じ名前のパラメータを持つものです.印刷出力は、メンバー変数が初期化されているかどうかを確認するためだけです.
class A
{
public:
A(int a): a(a){cout<<a<<endl;}
private:
int a;
};
初期化リストにthisが直接表示されないため、コンパイラはこのような重名の場合を処理します.すなわち、コンストラクション関数の初期化リストでthisを明示的に限定子にすることはできません.たとえば、次のコードはコンパイルできません.
A:this->a(a){}
3.あるクラスのコンストラクタ・アセンブリで別のコンストラクタを呼び出す方法
コンストラクション関数ではネストされた呼び出しは許可されませんが、異なるリロード形式を呼び出すことができます.例えば、次のコードです.(面接のテーマであることに注意してください)
struct CLS
{
int m_i;
CLS( int i ) : m_i(i){}
CLS(){CLS(0);}
};
int main()
{
CLS obj;
cout << obj.m_i << endl;
return 0;
}
出力はいくらですか?
---------------------------------------------------------------------------
答えは未知だm_iは初期化されていない変数であり、野値である.
"CLS(0);"の文は、一時的なCLSオブジェクトを作成し、そのオブジェクトのメンバーm_を表す.iは0に初期化されます.現在のオブジェクトの値は初期化されていません.
コンストラクション関数クラスが別のコンストラクション関数を呼び出す必要がある場合はplacement new演算子を使用する必要があります.コードは次のとおりです.
struct CLS
{
int m_i;
CLS( int i ) : m_i(i){}
CLS()
{
new (this)CLS(0);
}
};
placement newについて知らない場合は、c++primerまたはTCPLを見ることをお勧めします.
c++11では、上記の機能は、構造関数を委任または継承する形で直接実現することができる.
struct CLS
{
int m_i;
CLS( int i ) : m_i(i){}
CLS():CLS(0){}
};
4.ソリューション
ここまで書きます.コンストラクション関数の初期化リストでthisを参照する場合の基本的な理解では、本明細書で最初に提案した問題を次のコードで解決できます.
class Context;
class Ref
{
public:
Ref(Context&context):context(context){}
private:
Context &context;
};
class Context
{
public:
Context():ref(*this){}
private:
Ref ref;
};
次の質問を繰り返します.あるクラスのコンストラクション関数で別のオブジェクトのコンストラクション関数を呼び出し、thisを使用して参照メンバーを初期化する必要があります.
クラスContextは、そのコンストラクション関数の初期化リストでthisによってRefのコンストラクション関数を呼び出します.
5.参考資料
[1]一つの問題からC++におけるコンストラクタ呼び出しコンストラクタhttp://www.cnblogs.com/chio/archive/2007/10/20/931043.html
[2]c++1つのコンストラクタが別のコンストラクタを呼び出すhttp://www.cnblogs.com/ayanmw/archive/2012/08/20/2647808.html