スコープ
識別子の衝突
C言語を熟知している型であれば、ローカル変数名とグローバル変数名が同じだったとき
関数内で変数にアクセスすればどうなるか、すでにご存知だと思います
同様の現象がクラスのメンバ関数内とメンバ変数で発生します
メンバ関数内のローカル変数名と、同クラスのメンバ変数名が同じだった時です
次のプログラムを実行した時のことを考えてください
#include <iostream>
using namespace std;
class Kitty {
public:
char *str;
void print(char *);
};
void Kitty::print(char *str) {
cout << str;
}
int main() {
Kitty obj;
obj.str = "Kitty on your lap";
obj.print("Di_Gi_Gharat");
return 0;
}
Kittyクラスのメンバ関数 print() の仮引数の変数名が str であり
Kittyクラスのメンバ変数 str と同一です
print()メンバ関数を実行すると、予想どおりローカル変数を優先します
つまりこの場合、仮引数の str を標準出力に表示します
結果として Di_Gi_Gharat という文字列が画面に表示されたはずです
これを解決するのに、メンバ関数では内部でメンバ変数を明示することが可能です
こうすれば、同時にメンバ関数内ローカル変数と、メンバ変数を扱えます
ローカル変数との衝突や、メンバ変数であることを明示したいとき
メンバ関数では スコープ解決演算子 を用いてクラスを指定します
class-name::member;
class-nameは、そのメンバのクラス名を、
memberには、指定するクラスのメンバ名を指定します
#include <iostream>
using namespace std;
class Kitty {
public:
char *str;
void print(char *);
};
void Kitty::print(char *str) {
cout << str << '\n';
cout << Kitty::str << '\n';
}
int main() {
Kitty obj;
obj.str = "Kitty on your lap";
obj.print("Di_Gi_Gharat");
return 0;
}
今度のプログラムのprint()メンバ関数は
メンバ変数とローカル変数 str をスコープ解決演算子で区別しています
最初に出力する str は仮引数で得た文字列、Kitty::str はKittyクラスのメンバ変数を示しています
グローバルスコープ
さらにC++では、グローバル変数を関数内で明示することができます
先ほどのスコープ解決演算子と用いることで、全ての位置の変数を表せます
グローバル変数を関数内で明示するには グローバルスコープ解決演算子 ( :: ) を使用します
::var;
varにはグローバル変数名を指定します
ご覧のとおり、スコープ演算子はクラスを指定しましたが
グローバル変数は、何も指定せずに演算子と変数名で構成されます
#include <iostream>
using namespace std;
char *str = "Kitty on your lap\n";
int main() {
char *str = "Card Captor Sakura\n";
cout << str;
cout << ::str;
return 0;
}
グローバル変数 str と main() 関数内のローカル変数 str が存在しています
main()関数で、グローバルスコープ解決演算子が用いられているのがわかると思います
スコープ演算子を用いることで、それぞれの位置の変数を指定できるだけでなく
このように、変数が宣言された場所を明示することで保守性を高めることもできます
もちろん、冗長になるのが嫌であれば省略してもかまいません
以下のプログラムは、これまでのスコープ演算子の使い方をまとめたプログラムです
#include <iostream>
using namespace std;
char *str = "Di_Gi_Gharat\n";
class Kitty {
public:
char *str;
void print(char *str);
} obj ;
void Kitty::print(char *str) {
cout << str << Kitty::str << ::str;
}
int main() {
obj.str = "Kitty on your lap\n";
obj.print("Card Captor Sakura\n");
return 0;
}
もちろん、名前の衝突は変数だけではなく関数も同様です
つまり、関数の位置もスコープ変数を用いて明示することができます
#include <iostream>
using namespace std;
void function() {
cout << "Di_Gi_Gharat\n";
}
class Kitty {
void function();
public:
Kitty();
} obj ;
Kitty::Kitty() {
::function();
Kitty::function();
}
void Kitty::function() {
cout << "Kitty on your lap\n";
}
int main() {
return 0;
}
グローバルな関数(C言語の通常な関数) function() と
Kittyクラスのプライベートエリアの function() が定義されています
Kitty()コンストラクタで、スコープ演算子を用いてそれぞれを呼び出しています
::
スコープ解決演算子です
グローバルな位置の識別子を明示します
class::member
::declarators
class - クラス名を指定します
member - クラスのメンバ名を指定します
declarators - グローバル変数名を指定します