C++プライベートメンバー変数の理解
6439 ワード
プライベートメンバー変数の概念は、privateキーワードで宣言され、クラスの実現部分であり、外部に公開されず、オブジェクトの外部にオブジェクトにアクセスできないプライベートメンバー変数である.
しかし、コピーコンストラクタと付与子関数を実現する際に、関数内でオブジェクトを利用してプライベートメンバー変数に直接アクセスするため、困惑する.以下、具体的な例で説明する.
疑問:なぜ31行目と37行目のコードはコンパイル可能で、43行目と44行目のコードはコンパイルエラーを発生しますか?
このような疑問の原因は、自分のプライベートメンバー変数に対する理解が誤っているためであり、パッケージはコンパイル期間の概念であり、オブジェクトではなくタイプに対して、クラスのメンバー関数で同じタイプのインスタンスオブジェクトにアクセスできるプライベートメンバー変数である.
具体的な解析は以下の通りである:変数valueの記号からどのように解析する分析である.
1.シンボルの検索フィールドの決定
37行目のコードのように、コンパイラがvalue変数を発見すると、value変数が属するオブジェクトrhsのクラスドメインでシンボルが検索される.
2.現在のドメインにアクセスできる記号を特定
第1のステップから分かるように、現在検索ドメインはクラスドメインであり、printCTest関数はCTestクラス体にあるので、printCTestはCTestクラスのすべての変数(プライベートメンバー変数を含む)にアクセスすることができ、valueシンボルはCTestクラスドメインで発見する.
43行目のコードのように、main関数はCTestクラスにないので、main関数はCTestクラスドメインのプライベートメンバー変数にアクセスできない.
3.シンボルが見つかりました.コンパイルはパスしました.
クラスメンバー変数のアクセス権限はコンパイラによって強要され、コンパイラはvalueを見つけることができ、コンパイルによって自然にvalue変数の値にアクセスすることができる.
直感的には、37行目のコードにおけるvalueシンボルの検索ドメインは、オブジェクトrhsに対応する役割ドメインであるべきであると考えられるが、C++コンパイラの実現は、オブジェクトrhsのクラスドメインでvalueシンボルを検索することである.
啓発:一部の直感は頼りにならないので、その背後の実現原理を深く分析しなければならない.
補足:mainでsetまたはget関数を呼び出してこの問題を回避します.
References: http://www.cnblogs.com/dwdxdy/archive/2012/07/17/2595741.html
しかし、コピーコンストラクタと付与子関数を実現する際に、関数内でオブジェクトを利用してプライベートメンバー変数に直接アクセスするため、困惑する.以下、具体的な例で説明する.
1 class CTest {
2 public:
3 CTest(int i);
4 CTest(const CTest& rhs);
5 CTest& operator=(const CTest& rhs);
6 void printCTest(const CTest& rhs);
7 private:
8 int value;
9 };
10
11 CTest::CTest(int i):value(i)
12 {
13 cout<<"Contructor of CTest"<<endl;
14 }
15
16 CTest::CTest(const CTest& rhs):value(rhs.value)
17 {
18 cout<<"Copy contructor of CTest"<<endl;
19 }
20
21 CTest& CTest::operator=(const CTest& rhs)
22 {
23 cout<<"Assign function of CTest"<<endl;
24 }
25
26 CTest& CTest::operator=(const CTest& rhs)
27 {
28 cout<<"Assign function of CTest"<<endl;
29 if(this == &rhs)
30 return *this;
31 value = rhs.value; //
32 return *this;
33 }
34
35 void CTest::printCTest(const CTest& rhs)
36 {
37 cout<<rhs.value<<endl; //
38 }
39 int main()
40 {
41 CTest t = 1;
42 CTest tt = 2;
43 // cout<<t.value<<endl; // ,
44 // cout<<tt.value<<endl; // ,
45 t.printCTest(tt);
46 }
疑問:なぜ31行目と37行目のコードはコンパイル可能で、43行目と44行目のコードはコンパイルエラーを発生しますか?
このような疑問の原因は、自分のプライベートメンバー変数に対する理解が誤っているためであり、パッケージはコンパイル期間の概念であり、オブジェクトではなくタイプに対して、クラスのメンバー関数で同じタイプのインスタンスオブジェクトにアクセスできるプライベートメンバー変数である.
具体的な解析は以下の通りである:変数valueの記号からどのように解析する分析である.
1.シンボルの検索フィールドの決定
37行目のコードのように、コンパイラがvalue変数を発見すると、value変数が属するオブジェクトrhsのクラスドメインでシンボルが検索される.
2.現在のドメインにアクセスできる記号を特定
第1のステップから分かるように、現在検索ドメインはクラスドメインであり、printCTest関数はCTestクラス体にあるので、printCTestはCTestクラスのすべての変数(プライベートメンバー変数を含む)にアクセスすることができ、valueシンボルはCTestクラスドメインで発見する.
43行目のコードのように、main関数はCTestクラスにないので、main関数はCTestクラスドメインのプライベートメンバー変数にアクセスできない.
3.シンボルが見つかりました.コンパイルはパスしました.
クラスメンバー変数のアクセス権限はコンパイラによって強要され、コンパイラはvalueを見つけることができ、コンパイルによって自然にvalue変数の値にアクセスすることができる.
直感的には、37行目のコードにおけるvalueシンボルの検索ドメインは、オブジェクトrhsに対応する役割ドメインであるべきであると考えられるが、C++コンパイラの実現は、オブジェクトrhsのクラスドメインでvalueシンボルを検索することである.
啓発:一部の直感は頼りにならないので、その背後の実現原理を深く分析しなければならない.
補足:mainでsetまたはget関数を呼び出してこの問題を回避します.
References: http://www.cnblogs.com/dwdxdy/archive/2012/07/17/2595741.html