- ベストアンサー
クラスのインスタンスって何者?
データ用クラスのインスタンスなのですが、以前 「クラス名 利用名;」 で使うと毎回別のインスタンスを呼び出すらしく値が空になるトラブルが起き 「static クラス名 利用名;」 とすれば常に同じインスタンスになるからそれを使いなさいと教えられました。 以後ずっとこれを使ってきたのですが、 ヘッダーファイルAに記述したデータクラスを ソースファイルAで「static クラス名 利用名;」 ソースファイルBで「static クラス名 利用名;」 と利用名を完全に同じにしてもエラーが出ず(ソースのヘッダ領域なのに) ソースファイルAでそのデータクラスに入れたデータは ソースファイルBでは利用できず空になっていました。 極当たり前の何かを私はわかってないから こういうトラブルが起きているんだと思うのですが、 クラスのインスタンスって何者なんでしょうか? どうすれば複数のソースから1つのデータクラスを作り上げ 全体で利用できるように出来るのでしょうか?
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
C++におけるクラスの特徴のひとつに、 「組み込みのデータ型(int や double) と、限りなく同じような書式で使える」と いう点があります。 つまり、今回のお話は、クラス特有のお 話ではなく、 クラス名 利用名; は、「クラス名」という型の、利用名と いう変数についての取り扱いと同じです。 ※ちなみに、クラス本来の意味は、もう ちょっと違います。ご質問に関しては、 ユーザーが定義した型、インスタンスは、 その(ユーザーが定義した型)具体的な 変数という風に考えてみればいいかなと 思います。 最初にあった、static の有無で、毎回初 期化するかどうかが違ってくるというのは、 一般の「自動変数」と「静的(static) 変数」の違いなので、そういう方面を調べ てみてください。 変数には(インスタンスにも)スコープ というものがあって、 ・関数の中で宣言したものはその外では 見えない ・{……} の中で宣言した変数は、その外 では見えない ・ファイルの一番外側(どれかのの関数 の中でなくで定義した変数は、 それ だけでは他のファイルからは見えない ・ついでにいえば、ファイルの一番外側 で、static つきで宣言した変数は、 どうあがいても外部から見えない というルールがあります。 以上を言い換えると、 ・別々の { …… } の中で宣言した変数は、 たとえ同じ名前でも、全く別物。 ・別々のファイルで宣言した変数はたとえ 同じ名前でも、全く別物。 となります。 付け加えれば、共通のヘッダファイルの中で 宣言したものも、別々のソースに、include した時点で、「別々のファイルに宣言された もの」となって、これまた、別物。 さて、結論に入ります。 【基本】 1)ひとつのソースファイルで、実体を宣言する クラス名 利用名; ※このとき、static はなし。別のファイルでも 参照したい場合、一番外側に宣言します。 (グローバル変数の扱いになる) 2)それを使うその他のファイルでは、「外部宣言」 extern クラス名 利用名; これで、どこからでも、参照することができます。 【応用】 こちらは、 http://oshiete1.goo.ne.jp/qa3670390.html でも、紹介していました。 1)共通のヘッダファイルには、例えば、 以下のように記述する #if defined(GLOBAL_HERE) #define EXE #else #define EXT extern #endif EXT クラス名 利用名; 2)ひとつのソースファイルに限定して、以下のよう に include する #define GLOBAL_HERE #include "ヘッダファイル" 3)その他のソースファイルでは、GLOBAL_HERE を 定義せずに単純に、 #include "ヘッダファイル" で include する。 ただし、一般的には、グローバル変数は、設計的に 危険を伴いやすいので、クラスのインスタンス自体を 各関数の引数として渡す方が、お勧めできます。
その他の回答 (4)
- Tacosan
- ベストアンサー率23% (3656/15482)
#2 のお礼にある「ソースAのメインループから~」のところだけど, 実際問題としてあなたがどのように書いたのか分からないので原因など推測のしようもありません. 回答者の超能力に頼る書き方はしないでください. 問題がおきる (なるべく簡単な) コードを示したうえで ・あなたがどのような動作を期待しているのか ・実際にはどのような動作をしたのか を書いてください. あと, 念のためだけど処理系も.
お礼
説明が下手で申し訳ないです。 そのコードは破棄して再現が不可能なので申し訳ありません。 無事現在の全ての問題と疑問は解決できましたが、今後気にかけるようにします。 ご回答ありがとうございました。
- Yanch
- ベストアンサー率50% (114/225)
> staticの本来の意味は一応は理解しているのですが、 グローバ変数に、static キーワードをつけると、アクセススコープがソースプライベートになるんだよ。 クラスは関係ないですね。
お礼
なるほど。 ソース内でのみ使う共通の変数なんかはそれで覆うと 結構開発が楽になる という事なんですね。(名前被る心配もしなくて良いとなると。) これは便利そうです。ありがとうございます。
- 麻野 なぎ(@AsanoNagi)
- ベストアンサー率45% (763/1670)
「ソースBの一番外側」という表現ですが、こ れは具体的にどこでしょうか? 「内容が消えた」ということですから、本当に は、「一番外側」に書かれてはいなかったとい うことになります。 例えば、「同じファイル」の中で、 class BClass; void funcB() { BClass Bmenber; ..... } main() { for (i = 0; i < 100; i++) { funcB(); } } と書かれてたなら、funcB() が呼び出される たびに、Bmember は、「作り直されます」 これは auto 変数(自動変数)と同じ挙動で、 気持ちとしては、書かれた場所を通過するた びに中身が新しくなります。 これを避けるためには、 void funcB() { static BClass Bmenber; ..... } とします。 これが、static 変数(静的変数)の挙動と なり、プログラムの実行に「先だって」一度 だけ生成されます(必要により初期化も) さて、「一番外側」とは、 class BClass; BClass Bmenber; void funcB() { ..... } main() { for (i = 0; i < 100; i++) { funcB(); } } と、どの関数にも属さない形で記述するもので、 これが、グローバル変数となります。 グローバル変数も、プログラムの実行に「先 だって」一度だけ生成・初期化されます。 ですから、この位置にあれば、static がなく ても、プログラムの実行中に、再度生成される ことはありません。 さて、最後に、グローバル変数の位置(関数 の外)で、static を付けると、これは、「静 的変数」とは別の意味を持ちます。 グローバル変数は、 BClass Bmenber; だけであれば、他のファイルで、 extern BClass Bmember; と宣言することで、アクセス可能となります。 これに対して、 staic BClass Bmenber; と指定したもの(関数の外側で)は、その他の ファイルからは、一切アクセスできなくなります。 この点で、 ・関数の中で static 宣言したもの ・関数の外で static 宣言したもの は、static の意味が異なるのが、C++の 変則的なところです。 グローバル変数が「怖い」のは、変数の値が おかしくなったときに、どこで(もしくは、 どのファイルで)その、おかしな値をセット しているか容易にわからないところです。 この「怖さ」を軽減するために、ひとつのファ イルの中だけで(しかし、複数の関数から) 参照する必要のあるものは、関数の外側で、 static を付けて宣言します。 こうすれば、「少なくとも、そのファイルの中の 関数しか変数をいじっていない」とわかるから です。
お礼
おおおおお・・・ありがとうございます・・! >「内容が消えた」ということですから、本当に >は、「一番外側」に書かれてはいなかったとい >うことになります。 なるほど、つまり毎回内容が消えてしまっていたのは 恐らく私がそこを間違えて関数の内側に書いてしまっていたからで、 普通は外側に書いていれば消える事は無いのですね、 今までずっとつっかえていた物が取れました・・! 本当にありがとうございます・・! >・関数の中で static 宣言したもの >・関数の外で static 宣言したもの > >は、static の意味が異なるのが、C++の >変則的なところです。 私が疑問を抱えていたもう1つはコレだったのですね。 staticについては勉強しなおそうと思います。 >グローバル変数の怖さ なるほど・・プログラムが肥大化すると たったそれ1つで膨大な手間と労力を取られるのですね。 数が少ない内は意識してられますが増えると極めて危険なのでしょうね・・。 なるべくグローバル変数を使わない設計をできるよう 色々と勉強して行こうと思います。 前回のご助言から、本当に色々ありがとうございました。 長い間恐々使っていたコードの疑問に こんなに丁寧なお答えを頂けるとは思ってすらいませんでした。 何度も読み返してしっかり頭に叩き込もうと思います。ます。 本当にありがとうございました・・!
- Tacosan
- ベストアンサー率23% (3656/15482)
状況がよくわからないので, できれば具体的なソースで「こんなことをしたいけどこのソースだとこんな問題がある」と書いてもらえませんか? あと, 「ソースのヘッダ領域」とは何でしょうか? 「ヘッダ領域」を表す特殊な標識を使う処理系なのでしょうか? と書いておくけど, 本題としてはクラスは無関係で「static の意味が理解できていない」だけのような気がする.
お礼
ご回答ありがとうございました。 ソースの一番外側はどんな存在かと他所で聞いた時に ヘッダーと同じ扱いになる と聞いていたからそういう表現になってしまいました。すみません。 正しい呼び名がわからず申し訳ないです。 staticの本来の意味は一応は理解しているのですが、 質問の本題にある空になるトラブルからstaticをつけないと中身が空になる という先入観というか恐怖感が・・。 解りにくく、すみませんでした。
お礼
詳しい説明ありがとうございます。 2~3度読み返している内に段々解ってきた気がします。 >付け加えれば、共通のヘッダファイルの中で >宣言したものも、別々のソースに、include >した時点で、「別々のファイルに宣言された >もの」となって、これまた、別物。 そういう扱いになるのですね。 【基本】の扱いで上手く動作してくれました。 ありがとうございます orz 【応用】の方も一応やり方は理解できました。 #ifndefと同じ感 じなのですね。 >ただし、一般的には、グローバル変数は、設計的に >危険を伴いやすいので、クラスのインスタンス自体を >各関数の引数として渡す方が、お勧めできます。 そうなのですか。 そのやり方も調べて覚えて行こうと思います。 ありがとうございました。 しかし、最後に1つ気になる事が。 今回のトラブルでは無いのですが、私の質問内容の >>「クラス名 利用名;」 >>で使うと毎回別のインスタンスを呼び出すらしく値が空になるトラブルが起き >> >>「static クラス名 利用名;」 >>とすれば常に同じインスタンスになるからそれを使いなさいと教えられました。 >>以後ずっとこれを使ってきた―― これなのですが、 ソースAのメインループからソースBを何度も呼び出して処理する構造で、 ソースBからのみ利用するソースC D E Fそれぞれのクラスを ソースBの一番外側で 「クラス名 利用名;」 としたら、その一部クラスのメンバ全部が空になっている というトラブルが起きて 「static クラス名 利用名;」 と書きなさいと教えて頂いてから、怖くて常にこう使うようになってしまったのですが、 これはなぜ中身が消えてしまったのか お察しできる事例が有りますでしょうか・・? 今も中身が消える怖さでstaticを付けないのが怖いのですが・・。 本題の半分は解決したのですが、 よろしければこちらも教えて頂けると嬉しいです・・ orz