- ベストアンサー
クラスの外で宣言した変数について
初心者的な質問ですみません。 クラスの外で宣言した変数をそのままクラス内で使うことはできないのでしょうか? publicのメンバーにポインタの変数を作ってそこにアドレス指定するか、setするメソッドを作るしかないのでしょうか? もしクラスの外で宣言した変数をそのままクラス内で使えないのは、スコープ的にどういう理由で使えないのか教えて下さい。 クラス内クラスだと子クラスは親クラスの変数を参照できますが、それとは違うのでしょうか? どうぞよろしくお願い致します。
- みんなの回答 (13)
- 専門家の回答
質問者が選んだベストアンサー
■グローバル変数を扱う難しさの例 ○マルチスレッドのプログラム 変数Aをスレッド1とスレッド2から読み書きする処理がある場合、スレッド間で同期、または排他ロックなどをして同時に読み書きしないよう気を使う必要があり、プログラムもテストも大変難しくなります。 Windowsアプリの場合、ユーザインタフェース(画面とその入力)と内部処理が別スレッドで動かしたりすることも多いので意識してなくてもこういう問題が起こる場合があります。 ○複数人で開発するプログラム グローバル変数を他の人のプログラムで読み書されていたら自分の意識外での影響があったりします。これをメンテナンスするのは大変ややこしいことになります。 ○それでもグローバル変数を使う場合 プログラム全体を慎重に設計してそれでもグローバル変数を使う場合もないことはないです。ただし、そのリスクとコストをわかった上で使います。例えば既にあるプログラムでグローバル変数を扱ってるけどもうこのプログラムは変更しない方針であるとか実際には理想通りなプログラムは少ないことも現実です。 プログラムの勉強をしている場合はグローバル変数を使ったプログラムをそうでないものに書き換える練習をしてみるのも面白いです。いままで複雑だったプログラムが段々糸がほぐれてスッキリしたものになった時は気持ちのイイものです。 ■クラス化について プログラム全体が見えないので何とも言えませんが… >変数A >↓ >関数func1で変数Aを加工 >↓ >関数func2で変数Aを加工 >↓ >… >↓ >最終的な変数Aの値が決まる >これが5000行くらいかけて変数Aを処理していました。 5000行もある処理なら、処理の途中で中間型のデータが何種類かにまとまりませんか?そのデータのまとまりを分けて行ってからクラスにまとめていくとクラス化しやすいかもしれません。それか処理を階層的に分けていくと何度も使う末端の処理を別クラスにするとかで分けていく方法もあります。どでかい関数がドカーンとあるクラスは作ってもあまりメリットありませんので。
その他の回答 (12)
- Tasuke22
- ベストアンサー率33% (1799/5383)
ANo.9です。 手段だけ問われても回答のしようがありません。 この質問の回答は、設計しないと答えられません。 クラスは目的ではなく手段です。 設計とは手段の選択ではないです。 機能的強度や情報的強度をいかに持たすか、ということですので、 プログラムの目的から検討に入る必要があります。 その設計の結果、クラスが適当であればクラス化する、とかになる訳です。 プログラムの特殊性や設計能力の限界などで、どうしても共通データが 存在してしまったら、 共通データが関わる例外部分を極力範囲を小さくしてやることです。 共通データに関わらない部分を如何に多くするか、という検討がいいでしょう。 その検討が情報的強度を持つ部分の増加につながるでしょう。 また、それらの問題に深く思いを馳せることにより、次回の設計に実を結ぶと思います。
お礼
再びのご意見ありがとうございました。 共通データが関わる部分を少なくするということを肝に銘じて設計し直してみます。 皆さんのいろいろなアドバイスを頂きまして本当に勉強になりました。 自分の勝手な考え方をしてしまって申し訳ございません。 でもご指摘いただいて非常に感謝しています。 これからもこちらで初心者的な質問をしてしまうと思いますが どうぞよろしくお願い致します。
- Tacosan
- ベストアンサー率23% (3656/15482)
変数A ↓ 関数func1で変数Aを加工 ↓ 関数func2で変数Aを加工 ↓ … ↓ 最終的な変数Aの値が決まる でどういうことをしたいのかよくわからんのだけど, そもそも「クラスにしなきゃならんのか」ってことを考えないとだめじゃないかな. もちろん ・「加工」している途中の値が必要なのか ・「加工」が全体で何段階あるのか などにも依存するところで, 「途中の値は不要」かつ「段階が少ない」なら 1つの関数にすればいいとも考えられる. ど~してもクラスにしたいなら「変数A の値」をコンストラクタでもらうのかなぁ. でも, この手の単純な処理は「クラス」にはあんまりふさわしくないと思うんだが....
お礼
例で書いたのはとても単純なのですが、それぞれの関数は非常に複雑なので クラスにしたほうがいいとプログラマに言われました。 ただ、他のプログラマの方がグローバル変数を使っていたのでそれを真似てみようと 思ってやってみたところ、今回のような疑問が出てきたのです。 (自分はプログラマではありません)
- wormhole
- ベストアンサー率28% (1626/5665)
もしかしてC++ではなくて、C++/CLIでマネージド型をグローバル変数で扱おうとしてるとか・・・ >そして外部変数の値をそのクラスで加工するのに、いちいちset,getしたり、質問にあるように外部変数のアドレスをクラス内から参照して加工していましたが、関数だと簡単に加工できるのになぜクラスだと煩わしいことをしないと外部変数にアクセスできないのか、どのサイトや参考書を見ても書いていないので疑問に思い、こちらで質問させて頂きました。 グローバル変数を簡単にアクセスできるからという理由だけで使われているのなら、そのメリット・デメリットについてよく考えてみる事をお勧めします(サイトや参考書を探しても見つからないということはないです)。 これはC++やC固有の話ではなくてプログラミング全般について有用なことです。 むしろプログラミング初心者でもない人が考えたことないとかいう方が私は不思議に思います。
お礼
ありがとうございます。 クラスについては使い始めたのはここ1週間くらいです。 それまではクラスがない言語でした。 なので初心者と同じくらいの知識しかなくいろいろと疑問が起きたのです。 とりあえずグローバル変数がお勧めできない理由はわかってきました。 調べ方が悪かったようなのでもう少しいろいろ調べてみようと思います。
- Tasuke22
- ベストアンサー率33% (1799/5383)
理由ということで、おさわりだけですけど。 クラスの存在目的に、独立性とか隠蔽性とかあるのですが、目的は勿論、エラーの出難さ、メインテナンス性、読みやすさなどですけど。 その隠蔽性が簡単に失われるからです。 つまり、共通データによって、クラスが他のクラスやモジュールと深く結びつき、クラスの独立性が失われる訳です。 昔のサブルーチンとかモジュールとか関数というものはそんな設計でした。 それを反省してできたのがクラスといっても過言ではありません。 それを抜け道を探すように、昔の悪弊を再現したらつまらないでしょう。 昔のものは形だけプログラム分割されていても、共通データで深く結びつき、意味的には全く分割されていなかったようなものが多かったですね。 つまり物凄く複雑なコードが多かった訳です。 共通データが必要であることに、設計の根本的な問題を検討するべき、ということです。
お礼
ありがとうございます。 詳しく説明していただいて感謝します。 >共通データが必要であることに、設計の根本的な問題を検討するべき、ということです。 この点ですが、どんなプログラムでも共通のデータは極力存在しないほうがいいということでしょうか? そうするとクラス間でのデータの受け渡しはset,getメソッドを作ってやり取りするのが普通なのですか? C++で作り直す以前の言語はクラスも構造体もないような貧弱な言語だったので今回クラスを初めて使ったのでここで戸惑っています。 今までは 変数A ↓ 関数func1で変数Aを加工 ↓ 関数func2で変数Aを加工 ↓ … ↓ 最終的な変数Aの値が決まる という手続き型で処理していました。 これが5000行くらいかけて変数Aを処理していました。 これをクラスにするというそもそもこの5000行くらいの処理を一つのクラスにして、変数Aをメンバーにし 関数func1, func2をメソッドにすればいいのですか? すでに複数のクラスもたくさん作っているので、一番外枠の大きなクラスって必要なのかな?と思って大きなくくりのクラスは作らずに変数Aをグローバル変数にしてC++で書き直していたのです。
- Tacosan
- ベストアンサー率23% (3656/15482)
本当に「完全なプログラム」を出されても大抵は困ったりするんですが, そうはいっても「同様の問題が発生するプログラム」を出してもらわないとどうにもならないんですね. 実際, #1 へのお礼に挙げてもらったプログラムをコンパイルすると, #5 で指摘されているように a については問題なく printf に対して「宣言されていない」というエラーが出るはずなんです. ひょっとして, あれだけをコンパイルしてもあなたのところでは (printf ではなく) a に対してエラーが出るのでしょうか? もしそうだとしたら, エラーメッセージを全部出してもらえないでしょうか?
- wormhole
- ベストアンサー率28% (1626/5665)
>c++ができて、c#ができないのはなぜでしょうか? C# グローバル変数 で調べればわかります。 >あとお勧めしない理由はなんですか? クラスの知らないところでクラスの動作に影響を及ぼせますし、 別の見方をすればいつ誰がそれを書き換えるのかわからないからです。
お礼
ありがとうございます。 調べてみましたらお勧めしない理由も書かれていました。
- Tasuke22
- ベストアンサー率33% (1799/5383)
皆さんがお勧めできないと言っていることについて。 多分、こういうことはやっちゃイカン、ということを理解するのに数年はかかると思います。 クラスの存在意義が失われるというか、なんのためのクラスなん? ということを行おうとしていますね。
お礼
ありがとうございます。 >多分、こういうことはやっちゃイカン、ということを理解するのに数年はかかると思います。 >クラスの存在意義が失われるというか、なんのためのクラスなん? ということを行おうとしていますね。 はい、そういうところがまだ理解できていないのだと思っています。 今までは外部にある変数をいろいろな関数を使って値を加工するようなプログラムを書いていました。 今回書き直すにあたって、複数の関数をクラスのメソッドにまとめました。 そして外部変数の値をそのクラスで加工するのに、いちいちset,getしたり、質問にあるように外部変数のアドレスをクラス内から参照して加工していましたが、関数だと簡単に加工できるのになぜクラスだと煩わしいことをしないと外部変数にアクセスできないのか、どのサイトや参考書を見ても書いていないので疑問に思い、こちらで質問させて頂きました。 その理由を教えていただけたら嬉しいです。
- kmee
- ベストアンサー率55% (1857/3366)
「宣言されていない識別子」はaじゃなくてprintfってことはないですか?
お礼
ありがとうございます。 aについてそういうエラーが出ました。 自分がやっている環境は素のVC++環境ではないので(大規模開発の一部)、特別なのかもしれません。
- Tacosan
- ベストアンサー率23% (3656/15482)
そのプログラムは C++ として正しくないけど, 例えば #include <cstdio> float a = 1; class CL { public: void test() { std::printf("a = %f\n", a); } } cl; int main() { cl.test(); return 0; } ってプログラムならまったく問題なくコンパイルできないとおかしい (手元の g++ 4.6.2 で動作することを確認済み). あなたのところで問題の出る「完全なプログラム」はありませんか? 使っているコンパイラはなんですか? ちなみにですが, 「クラス内クラスだと子クラスは親クラスの変数を参照できますが」ってところは言葉がかなり怪しいですよ. 「親」とか「子」とか書いちゃうと継承関係と思われかねない. そして, 「クラスの中で定義したクラスから外のクラスのメンバーを参照できるか」というと, C++ では static メンバーでないと無理です (アクセス可能性についてはどこでクラスを定義しても同じ). C# なら可能なので, この部分を読む限り C# と解釈するのが自然 (#3 で「C# っぽい」と書いた根拠はここ).
お礼
ありがとうございます。 >あなたのところで問題の出る「完全なプログラム」はありませんか? 使っているコンパイラはなんですか? 実は大規模開発の一部を担当していて、完全なプログラムはちょっとこちらには書けないんです。 コンパイラはVC++のを使っています。 >ちなみにですが, 「クラス内クラスだと子クラスは親クラスの変数を参照できますが」ってところは言葉がかなり怪しいですよ. 「親」とか「子」とか書いちゃうと継承関係と思われかねない そうでしたね。気をつけます。 >そして, 「クラスの中で定義したクラスから外のクラスのメンバーを参照できるか」というと, C++ では static メンバーでないと無理です 了解しました。 ちなみに、大規模開発でなぜ初心者の私がC++を書いているのかは、実は何年も別の言語で書いていたものをC++で作りなおすことになったのでC++は初心者ということです。
- Tacosan
- ベストアンサー率23% (3656/15482)
ああ, 質問の文章をよく見たら C# っぽい気がしてきた. ということは #2 の最後の 1文かな?
お礼
ありがとうございます。 c++です…。
- 1
- 2
お礼
グローバル変数の扱いについて詳しくご説明頂きましてありがとうございました。 他の方のご意見や、そのような解説をしているサイトも見つかり、だいたい一致したご意見ですね。 クラス化については一緒に仕事をしているプログラマの方に設計を見てもらうことにしました。 非常に参考になるご意見に感謝します。