No.11ベストアンサー
- 回答日時:
■グローバル変数を扱う難しさの例
○マルチスレッドのプログラム
変数Aをスレッド1とスレッド2から読み書きする処理がある場合、スレッド間で同期、または排他ロックなどをして同時に読み書きしないよう気を使う必要があり、プログラムもテストも大変難しくなります。
Windowsアプリの場合、ユーザインタフェース(画面とその入力)と内部処理が別スレッドで動かしたりすることも多いので意識してなくてもこういう問題が起こる場合があります。
○複数人で開発するプログラム
グローバル変数を他の人のプログラムで読み書されていたら自分の意識外での影響があったりします。これをメンテナンスするのは大変ややこしいことになります。
○それでもグローバル変数を使う場合
プログラム全体を慎重に設計してそれでもグローバル変数を使う場合もないことはないです。ただし、そのリスクとコストをわかった上で使います。例えば既にあるプログラムでグローバル変数を扱ってるけどもうこのプログラムは変更しない方針であるとか実際には理想通りなプログラムは少ないことも現実です。
プログラムの勉強をしている場合はグローバル変数を使ったプログラムをそうでないものに書き換える練習をしてみるのも面白いです。いままで複雑だったプログラムが段々糸がほぐれてスッキリしたものになった時は気持ちのイイものです。
■クラス化について
プログラム全体が見えないので何とも言えませんが…
>変数A
>↓
>関数func1で変数Aを加工
>↓
>関数func2で変数Aを加工
>↓
>…
>↓
>最終的な変数Aの値が決まる
>これが5000行くらいかけて変数Aを処理していました。
5000行もある処理なら、処理の途中で中間型のデータが何種類かにまとまりませんか?そのデータのまとまりを分けて行ってからクラスにまとめていくとクラス化しやすいかもしれません。それか処理を階層的に分けていくと何度も使う末端の処理を別クラスにするとかで分けていく方法もあります。どでかい関数がドカーンとあるクラスは作ってもあまりメリットありませんので。
グローバル変数の扱いについて詳しくご説明頂きましてありがとうございました。
他の方のご意見や、そのような解説をしているサイトも見つかり、だいたい一致したご意見ですね。
クラス化については一緒に仕事をしているプログラマの方に設計を見てもらうことにしました。
非常に参考になるご意見に感謝します。
No.13
- 回答日時:
ANo.9です。
手段だけ問われても回答のしようがありません。
この質問の回答は、設計しないと答えられません。
クラスは目的ではなく手段です。
設計とは手段の選択ではないです。
機能的強度や情報的強度をいかに持たすか、ということですので、
プログラムの目的から検討に入る必要があります。
その設計の結果、クラスが適当であればクラス化する、とかになる訳です。
プログラムの特殊性や設計能力の限界などで、どうしても共通データが
存在してしまったら、
共通データが関わる例外部分を極力範囲を小さくしてやることです。
共通データに関わらない部分を如何に多くするか、という検討がいいでしょう。
その検討が情報的強度を持つ部分の増加につながるでしょう。
また、それらの問題に深く思いを馳せることにより、次回の設計に実を結ぶと思います。
再びのご意見ありがとうございました。
共通データが関わる部分を少なくするということを肝に銘じて設計し直してみます。
皆さんのいろいろなアドバイスを頂きまして本当に勉強になりました。
自分の勝手な考え方をしてしまって申し訳ございません。
でもご指摘いただいて非常に感謝しています。
これからもこちらで初心者的な質問をしてしまうと思いますが
どうぞよろしくお願い致します。
No.12
- 回答日時:
変数A
↓
関数func1で変数Aを加工
↓
関数func2で変数Aを加工
↓
…
↓
最終的な変数Aの値が決まる
でどういうことをしたいのかよくわからんのだけど, そもそも「クラスにしなきゃならんのか」ってことを考えないとだめじゃないかな. もちろん
・「加工」している途中の値が必要なのか
・「加工」が全体で何段階あるのか
などにも依存するところで, 「途中の値は不要」かつ「段階が少ない」なら 1つの関数にすればいいとも考えられる.
ど~してもクラスにしたいなら「変数A の値」をコンストラクタでもらうのかなぁ. でも, この手の単純な処理は「クラス」にはあんまりふさわしくないと思うんだが....
例で書いたのはとても単純なのですが、それぞれの関数は非常に複雑なので
クラスにしたほうがいいとプログラマに言われました。
ただ、他のプログラマの方がグローバル変数を使っていたのでそれを真似てみようと
思ってやってみたところ、今回のような疑問が出てきたのです。
(自分はプログラマではありません)
No.10
- 回答日時:
もしかしてC++ではなくて、C++/CLIでマネージド型をグローバル変数で扱おうとしてるとか・・・
>そして外部変数の値をそのクラスで加工するのに、いちいちset,getしたり、質問にあるように外部変数のアドレスをクラス内から参照して加工していましたが、関数だと簡単に加工できるのになぜクラスだと煩わしいことをしないと外部変数にアクセスできないのか、どのサイトや参考書を見ても書いていないので疑問に思い、こちらで質問させて頂きました。
グローバル変数を簡単にアクセスできるからという理由だけで使われているのなら、そのメリット・デメリットについてよく考えてみる事をお勧めします(サイトや参考書を探しても見つからないということはないです)。
これはC++やC固有の話ではなくてプログラミング全般について有用なことです。
むしろプログラミング初心者でもない人が考えたことないとかいう方が私は不思議に思います。
ありがとうございます。
クラスについては使い始めたのはここ1週間くらいです。
それまではクラスがない言語でした。
なので初心者と同じくらいの知識しかなくいろいろと疑問が起きたのです。
とりあえずグローバル変数がお勧めできない理由はわかってきました。
調べ方が悪かったようなのでもう少しいろいろ調べてみようと思います。
No.9
- 回答日時:
理由ということで、おさわりだけですけど。
クラスの存在目的に、独立性とか隠蔽性とかあるのですが、目的は勿論、エラーの出難さ、メインテナンス性、読みやすさなどですけど。
その隠蔽性が簡単に失われるからです。
つまり、共通データによって、クラスが他のクラスやモジュールと深く結びつき、クラスの独立性が失われる訳です。
昔のサブルーチンとかモジュールとか関数というものはそんな設計でした。
それを反省してできたのがクラスといっても過言ではありません。
それを抜け道を探すように、昔の悪弊を再現したらつまらないでしょう。
昔のものは形だけプログラム分割されていても、共通データで深く結びつき、意味的には全く分割されていなかったようなものが多かったですね。
つまり物凄く複雑なコードが多かった訳です。
共通データが必要であることに、設計の根本的な問題を検討するべき、ということです。
ありがとうございます。
詳しく説明していただいて感謝します。
>共通データが必要であることに、設計の根本的な問題を検討するべき、ということです。
この点ですが、どんなプログラムでも共通のデータは極力存在しないほうがいいということでしょうか?
そうするとクラス間でのデータの受け渡しはset,getメソッドを作ってやり取りするのが普通なのですか?
C++で作り直す以前の言語はクラスも構造体もないような貧弱な言語だったので今回クラスを初めて使ったのでここで戸惑っています。
今までは
変数A
↓
関数func1で変数Aを加工
↓
関数func2で変数Aを加工
↓
…
↓
最終的な変数Aの値が決まる
という手続き型で処理していました。
これが5000行くらいかけて変数Aを処理していました。
これをクラスにするというそもそもこの5000行くらいの処理を一つのクラスにして、変数Aをメンバーにし
関数func1, func2をメソッドにすればいいのですか?
すでに複数のクラスもたくさん作っているので、一番外枠の大きなクラスって必要なのかな?と思って大きなくくりのクラスは作らずに変数Aをグローバル変数にしてC++で書き直していたのです。
No.8
- 回答日時:
本当に「完全なプログラム」を出されても大抵は困ったりするんですが, そうはいっても「同様の問題が発生するプログラム」を出してもらわないとどうにもならないんですね. 実際, #1 へのお礼に挙げてもらったプログラムをコンパイルすると, #5 で指摘されているように a については問題なく printf に対して「宣言されていない」というエラーが出るはずなんです.
ひょっとして, あれだけをコンパイルしてもあなたのところでは (printf ではなく) a に対してエラーが出るのでしょうか? もしそうだとしたら, エラーメッセージを全部出してもらえないでしょうか?
No.6
- 回答日時:
皆さんがお勧めできないと言っていることについて。
多分、こういうことはやっちゃイカン、ということを理解するのに数年はかかると思います。
クラスの存在意義が失われるというか、なんのためのクラスなん? ということを行おうとしていますね。
ありがとうございます。
>多分、こういうことはやっちゃイカン、ということを理解するのに数年はかかると思います。
>クラスの存在意義が失われるというか、なんのためのクラスなん? ということを行おうとしていますね。
はい、そういうところがまだ理解できていないのだと思っています。
今までは外部にある変数をいろいろな関数を使って値を加工するようなプログラムを書いていました。
今回書き直すにあたって、複数の関数をクラスのメソッドにまとめました。
そして外部変数の値をそのクラスで加工するのに、いちいちset,getしたり、質問にあるように外部変数のアドレスをクラス内から参照して加工していましたが、関数だと簡単に加工できるのになぜクラスだと煩わしいことをしないと外部変数にアクセスできないのか、どのサイトや参考書を見ても書いていないので疑問に思い、こちらで質問させて頂きました。
その理由を教えていただけたら嬉しいです。
No.4
- 回答日時:
そのプログラムは 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++は初心者ということです。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Java java 飾子を付けること(public static・・・) ・コンソールへの出力処理はmainメ 2 2022/06/16 19:34
- その他(プログラミング・Web制作) どういうプログラムで組みますか?google colabでやってるんですけど、出来る方お願いします。 1 2022/07/06 09:28
- その他(プログラミング・Web制作) このプログラミングをどう組みますか? Googlecolabでやってるんですが、出来る方お願いします 1 2022/07/13 10:52
- その他(プログラミング・Web制作) どういうプログラムで組みますか?google colabでやってるんですけど、出来る方お願いします。 1 2022/07/17 18:41
- Java JavaのSingletonパターンのprivateの持つ意味が分かりません。 5 2022/06/12 10:38
- その他(プログラミング・Web制作) pythonのプログラムについての質問です。 1 2023/05/26 10:31
- Java javaの質問です 次の機能を有するメソッド4つを自クラスに作成し、実装したいです 【機能】 足し算 1 2022/06/15 17:49
- 学校 中2女子不登校です。中2の5月辺りからクラス替えの変化で1年の頃からのストレスによる頭痛が悪化し、体 2 2022/03/23 17:16
- Java javaのクラスの分け方について質問です。 APIの内部用と外部用でクラスを分けたいのですがインター 2 2022/04/26 16:06
- 高校 変なことを言ってしまう。 高校生です。私はクラスの前で先生に当てられたとき、つい変なことを言ってしま 6 2023/06/07 19:42
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
java eclipse 型に解決できません
-
グローバルIPとプライベートIP...
-
「天声人語」をインターネット...
-
3年間同じクラスになる確率
-
下記の問合せを行うクエリを、P...
-
サーブレット実行時のエラー
-
配列の重複する値とその個数を...
-
IPアドレスのクラスAを取得して...
-
自作のクラスファイルがインポ...
-
javaで画像ファイルの入出力方法
-
packageとimport の違いって?
-
tomcat上でのpropertiesファイ...
-
C#で OpenSSLで3DES
-
体育祭クラス全員参加のムカデ...
-
エクセルVBAでのwitheventsにつ...
-
河合塾のクラス分けについて
-
ASP.NETでのジェネリックの利用
-
クラスにアクセスできません。
-
複数のクラスで共通した関数を...
-
内部クラスを別ファイルに
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
河合塾のクラス分けについて
-
同じクラスにならない確率を教...
-
3年間同じクラスになる確率
-
「天声人語」をインターネット...
-
グローバルIPとプライベートIP...
-
配列の重複する値とその個数を...
-
java eclipse 型に解決できません
-
同一パッケージにあるクラスが...
-
私はクラスLINEにまだ入れてな...
-
老い先短い ジジィ が ふと 思う...
-
自作のクラスファイルがインポ...
-
どこからも呼ばれていない無意...
-
main()を持つクラスが2つ以上...
-
数学の計算問題。 3年間同じク...
-
クラス見てから 女の子5人 ネタ...
-
javaのコンパイルができません...
-
1 つのヘッダファイルに複数の...
-
重複エラーを解決するには
-
IPアドレスの3バイト目の呼び方
-
packageとimport の違いって?
おすすめ情報