グローバル変数、関数を全てのクラスでインクルードしたい。

[戻る]
オリバ 2007/01/25(木) 15:53:59
VC6 XPです。

メインダイアログクラスCMainDlg
メインダイアログから表示されるCChildADlg、CChildBDlg
と3つのクラスがあります。

さらに
GenericクラスCgenを作成しました。
このクラスはCMainDlg、CChildADlg、CChildBDlgで使いたいです。
よって、
インクルードしたいんですが、
StdAfx.hで"gen.h"をインクルードするのが普通ですか?
さらにこのとき、CChildADlgのメンバにCgen pGen;
を宣言するとエラーになります。

上と似た関係で
グローバルヘッダファイル(変数やデファイン定義を宣言)を全クラスから
コールするにはどのようにインクルードすればよいですか?

tetrapod 2007/01/25(木) 16:16:23
「普通か」という疑問に答えるためには母数のでっかいアンケートが必要。
俺の意見はあくまで俺の意見であって「普通か」の答えとはなりえない。
というわけで以下俺意見。

stdafx.h に自作の gen.h を #include したりはしない。
stdafx.h 中で #include するのは「まず絶対に変更の無い」ファイルのみ。
すなわち Windows/VisualC++ 側が用意したもの、ということは簡単に言うと
#include <....> と <> で囲むべきもののみ。

gen.h はもう完成済みで絶対に変更しない!ということならば
stdafx.h 中に書く、という人はいるかもしれないけど、俺はやんない。
普通に CMainDlg.cpp 中に #include "gen.h" するべし。
っていうかそういう「共通」なものが本当に必要?
グローバル変数なんてのは使わないに限るんだけど。
resource.h なんかは共通に使うけど、変更が多いから stdafx.h には書かない。

あと、エラーになる、って何エラーかわからんのにアドバイスできんよ。

オリバ 2007/01/25(木) 16:29:51
Cgenのクラスで状態遷移関数(50遷移ぐらい)を用意し、
CChildADlg、CChildBDlgでは同じ状態遷移を実行します。
違いは、パラメータ2つのみ。
だから、CChildADlg、CChildBDlgの両方に同じ記述をするのは時間もかかるし
無駄だと思ったのでこのような方法にしました。

>stdafx.h 中で #include するのは「まず絶対に変更の無い」ファイルのみ。
こういう意識はありました。

エラー内容は以下の通りです。
構文エラー : ';' が、識別子 'pGen' の前に必要です。
error C2501: 'Cgen' : 識別名を宣言するのに、型が指定されていません。
error C2501: 'pGen' : 識別名を宣言するのに、型が指定されていません。

Blue 2007/01/25(木) 16:39:12
> エラー内容は以下の通りです。
そのクラス(CChildADlg)のヘッダに #include "gen.h" と記述していないのでしょう
か?

オリバ 2007/01/25(木) 16:42:04
インクルードがらみでもうひとつ質問があるのですが・・・

クラスをたくさん作ると"StdAfx.c"などがあるフォルダの直下に
ファイルがたくさんできてしまします。
そこで機能ごとにフォルダを作成し、そのフォルダの直下にファイルをおきました。
そのクラスのCファイルでも先頭で"StdAfx.h"をインクルードしてますが、
パスが違うため"../StdAfx.h"としないとだめなのでは?
しかし、このようにすると

fatal error C1010: プリコンパイル済みヘッダーの検索中に予期しない EOF を検出しました。

というエラーになります。
パスが違うのに
"StdAfx.h"だとエラーになりません。
なぜでしょうか?

オリバ 2007/01/25(木) 16:47:29
>そのクラス(CChildADlg)のヘッダに #include "gen.h" と記述していないのでしょう
>か?

してないですよ。
今してみましたが、同じ結果でした。

Blue 2007/01/25(木) 17:04:07
>してないですよ。
しなければ、CChildADlgがCgenってクラスが何者かわからないのでコンパイルできなく
て当然です。


>今してみましたが、同じ結果でした。
そんなことないと思いますが。一度リビルドしてみてはどうでしょうか?

>パスが違うのに
>"StdAfx.h"だとエラーになりません。
おそらく、コンパイル時にそのcppを基準に見てコンパイルしないからではないでしょう
か?
(たとえばdwpがあるフォルダを基準にしているとか。)

オリバ 2007/01/25(木) 19:07:35
"StdAfx.h"で"gen.h"をインクルードし、
CChildADlgのメンバ変数に
CGen m_CGen;
を宣言し、
CChildADlgクラス内でアクセスすることができました。

>おそらく、コンパイル時にそのcppを基準に見てコンパイルしないからではないでしょ
>うか?
多分そんな感じなんでしょうね!
ということは、"StdAfx.h"の階層にフォルダを作成し、そのフォルダ内に
クラスのcpp,hを置いても問題ないということですね?
クラスがたくさん増えると整理したくなります。。。
1つのフォルダだときたなくみえて!
ファイルを探すのも大変ですし!

PATIO 2007/01/26(金) 11:24:01
ちなみになんですが、

今言われているCgenと言うクラスに関しては別にグローバル変数と言うわけでも
無いみたいですね。単にとあるクラスを他のクラスのメンバーに使いたいと言う
事だけに見えます。私なら各クラスのヘッダーにインクルードしちゃうでしょうね。
その方が転用する時は都合が良いので。

プリコンパイルヘッダーを使用するにしている時に変更が多いヘッダーファイルを
Stdafx.hにインクルードしてると毎回プリコンパイルヘッダーの作り直しが行われるので
プリコンパイルヘッダーを使っている魅力が半減するかもしれません。
それでもソースファイル毎で無くなるからマシではありますが。

ITO 2007/01/26(金) 13:32:03
「Stdafx.h」でなく、アプリケーションクラス(CWinAppクラス)のヘッダファイル
に加えてみたらどうでしょうか。
 AppWizardでスケルトンを作成すれば、個々のクラスで定義されるはずです。
「Stdafx.h」はVisualCが管理しているヘッダーファイルです。
普通、SDK等で使うヘッダーファイル、MFCのヘッダファイル「Afx」で始まるヘッダファイルです。

オリバ 2007/02/01(木) 17:24:59
>ちなみになんですが、

>今言われているCgenと言うクラスに関しては別にグローバル変数と言うわけでも
>無いみたいですね。単にとあるクラスを他のクラスのメンバーに使いたいと言う
>事だけに見えます。私なら各クラスのヘッダーにインクルードしちゃうでしょうね。
>その方が転用する時は都合が良いので。

詳しく説明するとメインダイアログにボタンが10個あります。
このボタン押下でそれぞれのダイアログが表示されます。

上で示したジェネリッククラスは
この10個のダイアログクラスのうち8個で使用されます。
また、同じように8個のダイアログクラスで共通に使用する
ジェネリッククラスが10個ぐらいあります。


このような状況ではジェネリッククラスの定義を
どのようにするのが妥当でしょうか?

たいちう 2007/02/01(木) 18:00:55
> このような状況ではジェネリッククラスの定義を
> どのようにするのが妥当でしょうか?

妥当性を考えるには、ジェネリッククラスについての情報不足。


> 上で示したジェネリッククラスは
> この10個のダイアログクラスのうち8個で使用されます。

多くのダイアログクラスが同じようなイベントハンドラを
持っているような印象を受けます。
私ならダイアログクラスの基底クラスを検討すると思う。


> また、同じように8個のダイアログクラスで共通に使用する
> ジェネリッククラスが10個ぐらいあります。

もしかして、複数のダイアログクラスから、
共通のジェネリッククラスのインスタンスを見たいって事?

その場合、ダイアログの基底クラスのスタティックメンバとして持つか、
ジェネリッククラスのメンバをスタティックにする。

いずれにしろ、これ以上は情報不足。何をしたいのか書いてください。


# 私の書いてることが判りにくければ...
http://www1.kcn.ne.jp/~robe/cpphtml/html02/cpp02028.html

oid 2007/02/01(木) 19:38:14
それぞれのクラスが完全に独立してて
しかも、横の情報のつながりが無くて良いなら、

その何十個もあるラス全部を継承したクラスをがんばって作って
それひとつをインクルードするとかw

ハードルも高そうですが、すっきりするかもよ?

オリバ 2007/02/02(金) 13:41:29
詳しく説明します。
このアプリは基板の単体調整用ソフトです。

メインダイアログにあるボタンを押下することにより各基板のダイアログが表示されま
す。
基板は全部で9種類。
各基板の試験項目は20種類ほど。(基板により異なる)
各基板のダイアログに各試験項目のボタンを用意し、
ボタンを押下することにより、試験を開始し、
結果をリストボックスに表示します。
各基板ダイアログのOnTimerで状態遷移をします。
その時に共通の試験項目が10種類ほどあります。
例えば、メモリテストなど・・(試験範囲とアドレスが異なるのみ)
この試験をジェネリッククラスで状態遷移させ、
各基板ダイアログクラスから共通にアクセスしようとしています。
試験範囲などのパラメータを各基板ダイアログクラスから渡せば
試験の状態遷移は共通化することができます。

tetrapod 2007/02/02(金) 14:53:30
いや、だからフツーに #include すりゃいいぢゃん。
stdafx.h に書くのは個人的には絶対却下なので、こんな感じ。

--- generic.h ---
class generic_helper {...};
--- hoge1.h ---
#include "generic.h"
class CHogeDialog : public CDialog { ...
  generic_helper x;
};
--- hoge1.cpp ---
#include "StdAfx.h"
#include "hoge1.h"
...

必要なところにきっちり #include を記述すれば正しく動く。

もし何かが正しく動かないとしたら、それはソースコードの記述が悪い。
・#include の順番/位置が悪いとか
・多重 #include に対応してない記述してるとか
・#include "StdAfx.h" より前に何か書いてるとか

ソース開示なしには一般論しか言えないのであとはがんばってくれ。

「共通のなんたら」がいっぱいあるならたいちうさんのご意見を参考にしませう。

PATIO 2007/02/02(金) 17:11:48
基本的に言われている事はコードの共通化をしたいと言うだけの話に見えます。
(要は共通の処理をクラスとして纏める事で再利用したいと言う話)
各ダイアログにあるクラスが一箇所の状態遷移変数に対して更新を掛けたいとか
そういう話では内容に見えますけれど、違うのでしょうか?
ジェネリッククラスのインスタンスは各ダイアログクラスのメンバー変数として独立して
いて良いのでしょう?
ならば、色々考えるよりもそれを使う必要があるクラスのヘッダーファイルに
インクルードするのがもっとも単純でわかりやすい対応だと思います。

基本的にインクルードする必要があるかどうかはそのクラスの宣言を行う
ヘッダーファイルで行えるはずですし、そうしておく事でそのヘッダーファイルを
インクルードするだけでそのクラスが使えるようになるわけなので便利だと
思います。ただし、各ヘッダーファイルは適切に二重インクルード防止の処置を
行っている事が大前提ですけれど。
各ヘッダーファイルでのインクルードし忘れは、ビルド時に発覚するはずですから
問題ないでしょう。
各ヘッダーファイルへインクルードすると言う案の何処に問題があるのでしょう?
逆にその部分をはっきりさせないと話は堂々巡りするだけだと思います。
単にインクルードする手間が面倒と言う話なら
そういうもんだからインクルードしなさいとしか言えなくなりますけれども。

PATIO 2007/02/02(金) 17:15:13
ちょっと訂正。

> 基本的にインクルードする必要があるかどうかはそのクラスの宣言を行う
> ヘッダーファイルで行えるはずですし、

これは、

基本的にインクルードする必要があるかどうかの判断はそのクラスの宣言を行う
ヘッダーファイルで行えるはずですし、

の間違いです。
読み替えておくんまし。

オリバ 2007/02/02(金) 18:35:03
>各ダイアログにあるクラスが一箇所の状態遷移変数に対して更新を掛けたいとか
>そういう話では内容に見えますけれど、違うのでしょうか?
ジェネリッククラスで状態遷移をします。各ダイアログクラスの状態遷移からジェネリ
ッククラスの状態遷移関数を実行するかんじです。

>ジェネリッククラスのインスタンスは各ダイアログクラスのメンバー変数として独立し
>ていて良いのでしょう?
そのようにしています。
各ダイアログクラスで状態遷移を持っているので他のダイアログクラスとは完全に別物
です。

>基本的に言われている事はコードの共通化をしたいと言うだけの話に見えます。
>(要は共通の処理をクラスとして纏める事で再利用したいと言う話)
その通りです。説明がへたですいません。


>各ヘッダーファイルへインクルードすると言う案の何処に問題があるのでしょう?
それが一般的なのですね?
ジェネリッククラスは初めて作成したので扱いに少々疑問が生まれたのです。
アプリケーションクラス(CWinAppクラス)のヘッダファイルや
「Stdafx.h」でインクルードすることをみんな拒絶している理由が知りたいなと思いま
した。

オリバ 2007/02/02(金) 18:38:07
言い忘れましたが、
DLLのヘッダファイルはどこでインクルードするのが妥当ですか?
これも使用する各クラスのヘッダが望ましいですか?

Ban 2007/02/02(金) 19:56:04
> stdafx.h に書くのは個人的には絶対却下なので、こんな感じ。

この感覚は分かる気がします。(少なくとも私もstdafx.hには書かない)

Ban 2007/02/02(金) 19:58:29
> DLLのヘッダファイルはどこでインクルードするのが妥当ですか?
> これも使用する各クラスのヘッダが望ましいですか?

使うところでのみincludeして、依存関係が局所化できるようにする。
ヘッダ内でそのincludeが必要なら仕方がないが、
内部でしか使わないならソースの方にincludeする方がよいと、私なら思います。

オリバ 2007/02/02(金) 20:48:30
>この感覚は分かる気がします。(少なくとも私もstdafx.hには書かない)
みなさんそうなんですね。
ボクは特に意識しないでインクルードしていました。


>使うところでのみincludeして、依存関係が局所化できるようにする。
なるほど。たしかにそうですね。
ぼくもそのようにしてみます。


最初のほうにtetrapodさんが
>stdafx.h 中で #include するのは「まず絶対に変更の無い」ファイルのみ。
>すなわち Windows/VisualC++ 側が用意したもの、ということは簡単に言うと
>#include <....> と <> で囲むべきもののみ。
と言ってましたが、
みなさんもそうですか?

また、アプリケーションクラス(CWinAppクラス)のヘッダファイルで
インクルードするときはどのような時に行いますか?
みなさんの意見を聞きたいです。

Ban 2007/02/02(金) 23:34:03
> みなさんもそうですか?

みんなかどうかは知りませんが、私はほぼ同意見です。


> また、アプリケーションクラス(CWinAppクラス)のヘッダファイルで
> インクルードするときはどのような時に行いますか?

CWinApp のクラス定義で、インクルード先の定義が必要になるとき。
例えば、
CWinAppのメンバに実体の構造体などを持つ場合。

#include <foo.h>

CWinApp
{
  Foo foo;
};

オリバ 2007/02/03(土) 16:17:48
[[解決]]
了解しました。

みなさん、色々なご意見ありがとうございました。

古いスレッドには追加発言できません。