質問 |
||
| QNo.4024474 | includeファイルの読み込み追加の際のコインパイルエラー | |
|---|---|---|
| 質問者:kudamono10 |
VC初心者で初めて質問させて頂きます。 仕事でVC++6.0にて開発を行っています。 既設で正常に動作しているプロジェクトに対して ロジックを追加しなければいけないのですが、 その際、同プロジェクト内で定義されていない 変数を使用したく、includeファイルの 読み込みを追加(#include "aaa.h")し、参照しようと したのですが、以下のようなコンパイルエラーが 発生してしまいます。 '***' 定義されていない識別子です。 ***:追加したincludeファイル内にて定義されている 変数 紐付けがうまくいってないと思うのですが プロジェクトの設定画面にて、インクルードファイル のパスを確認したところ既設にてパスは存在して いました。 同様に依存関係を確認したところ、必要な ヘッダファイルは全てありました。 関係あるかはわかりませんが、クリーン→ビルド しても状況は変わりませんでした。 パスが通っているなら単純にインクルードファイルを 読みこんで参照すればいいと思うのですが、 何か他に必要なことがあるのでしょうか 初めての質問ということで、質問の仕方が 分かりづらい点もあるかと思いますが 宜しくお願い致します。 |
|
困り度:
|
||
| 質問投稿日時: 08/05/15 17:12 |
||
回答良回答20pt |
|
| ANo.9 | No.8 です。訂正。 大嘘ついてました。 > あと、CLS_bbb のメンバが protect: であったとしても、CLS_bbb *pbbb = pApp->ccc.pddd; が正しければ、pbbb-> の形でアクセスできます。 いえ、できません。できないのが正解です。 さて、このときに考え方は二つあります。 ・メンバーが protected: である以上、このメンバーを参照したくなるようなプログラムは設計的に間違っている。 ・設計的には間違っているが、特殊な事情があり、「掟破り」をしなければならない。 まず、いずれなのかを見極める必要があります。 その上で、「掟破り」の方法。 これは、派生クラスを作って、セッタやゲッタを定義するという方法があります。 たとえば、ベースクラスの int value が protected: の場合、これを参照すると。 class CLS_bbb_sub : public CLS_bbb { public: int get_value() { return value;} void set_value(int v) { value = v;} } これで、 // アプリケーションクラスのポインタを獲得 CLS_aaaApp *pApp = (CLS_aaaApp *)AfxGetApp(); CLS_bbb_sub *pbbb = dynamic_cast<CLS_bbb_sub *>(pApp->ccc.pddd); ここまで考えてみましたが、やっぱりだめのようですね。 上記雄 ccc.pddd が、CLS_bbb_sub だったら、これで対処できますが、実際には、違うクラスなのだから、上記の2行目で実行時エラーになりますね、きっと。 やはり、それは、アクセスしてはいけないメンバーなのでしょう。 |
|---|---|
| 回答者:AsanoNagi | |
| 種類:アドバイス どんな人:一般人 自信:参考意見 |
|
| 回答日時: 08/05/17 06:28 |
|
| |
| この回答へのお礼 | 返事が遅くなってしまいました。 回答ありがとうございます。 初心者である私にとって非常に分かりやすく説明してくださって 感謝しております。 おかげさまで問題は解決いたしました。 結論からいいますと >・メンバーが protected: である以上、このメンバーを参照したくな>るようなプログラムは設計的に間違っている。 ご指摘の通り設計的に誤っておりました。 考えてみれば、特にprotectedなメンバ関数などを他のプロジェクト のクラスから使用するなんておかしいですよね 調査したところロジックを追加するクラスのインクルードにて 同様なprotectedなメンバ変数・関数が用意されており、 それらを使用すればよいというなんともがっくりな おちでした。 では改めてありがとうございました。 |
回答 |
|
| ANo.8 | 残念ながらこれ以上は、クラス相互の関係がわからないと何とも言い難いです。 ただ、インクルードファイルにあるのは多くの場合、単なる定義です。 その実体は、それをインクルードしているファイルのどこかで定義されています。 ですから(単なる言葉の間違いかもしれませんが)インクルードファイルに定義してある変数を参照するというのは普通ありません。 このあたりが、理解の鍵になるかもしれません。 あと、 // アプリケーションクラスのポインタを獲得 > CLS_aaaApp *pApp = (CLS_aaaApp *)AfxGetApp(); > CLS_bbb *pbbb = pApp->ccc.pddd; ですが、AfxGetApp() の返値をわざわざ (CLS_aaaApp *) にキャスとしているのが不自然です。敢えてこうしたというのであれば、おそらく、AfxGetApp() の返すポインタは、CLS_aaaApp のサブクラスかベースクラスかどちらかのポインタかなと思います。 もしも、CLS_aaaApp のほうがサブクラスであれば、dynamic_cast というのを使ってみてください。その方が安全にキャストできますし、サブクラスのポインタに正しく変換してくれたかなと思います。 あと、CLS_bbb のメンバが protect: であったとしても、CLS_bbb *pbbb = pApp->ccc.pddd; が正しければ、pbbb-> の形でアクセスできます。 どうも、継承がらみで、サブクラスからベースクラスへのキャストか、この逆かが発生していて、そのあたりの処理がうまくいっていない気はします。 |
|---|---|
| 回答者:AsanoNagi | |
| 種類:アドバイス どんな人:一般人 自信:参考意見 |
|
| 回答日時: 08/05/16 14:29 |
|
| |
| この回答へのお礼 | この回答にお礼をつける(質問者のみ) |
回答 |
|
| ANo.7 | 直接回答していませんでした。 1点目 "aaa.h"の中で"bbb.h"を読み込んでおりさらに"bbb.h"の中で "ccc.h"を読み込んでいる場合において"ccc.h"内で定義されている 変数を使用したい場合"aaa.h"だけをプログラムで読み込んで、 直接変数名を指定して使用することは可能なのでしょうか (各ヘッダファイルの場所はプロジェクトが異なっていたりします) 可能です。 インクルードしたファイルに書かれていたのは、単に、「そう書かれていた」ように展開されるだけなので、 #include "ccc.h" の代わりに、同じところに ccc.h の中身を直接書いても同じことになります。 ただし、同じように ccc.h を取り込んでいるプロジェクトがある場合、ある日 ccc.h の内容が変更になったとします。 そのとき、この、「直接書いた」プロジェクトだけは、なぜか変更ができていなくて大騒ぎになったりすることがあるので、そのあたりの兼ね合いも必要です。 |
|---|---|
| 回答者:AsanoNagi | |
| 種類:アドバイス どんな人:一般人 自信:参考意見 |
|
| 回答日時: 08/05/16 12:39 |
|
| |
| この回答への補足 | 回答ありがとうございます。 変数をグローバル化して、共通に使用するようにする方法 について大変勉強になりました。 ただ現状況といたしましては 既設のソース内のインクルードファイルで 定義されている変数の属性を変える事は避けたいと考えております。 (正常に動作しておりどこに影響を及ぼすかがはかりかねない為) できれば既設のインクルードファイルの定義は変えず使用したい のです。 調査を進めていたところ他のプロジェクトのヘッダファイルにて 定義されている変数を参照する方法だと思うのですが、 既設のソースにて以下の様な処理を行っていました。 // アプリケーションクラスのポインタを獲得 CLS_aaaApp *pApp = (CLS_aaaApp *)AfxGetApp(); CLS_bbb *pbbb = pApp->ccc.pddd; ※ここでCLS_bbbが参照したい変数のあるクラス このあと追加ロジックとして pbbb-><参照したい変数> と記述したところコンパイルエラーはでなくなりました。 一部解決はしたのですが新たな問題として CLS_bbbに定義されている変数がprotectedのものがあり、 コンパイルエラーとなってしまいました。 その後、CLS_bbbクラスのサブクラスとすればよいのではと 考え、ロジックを追加するプロジェクトのヘッダファイルにて 以下の様に継承させてみたのですが同様にコンパイルエラー となってしまいます。 ※protectedをpublicに変えるのはその変数がDBがらみの アクセス変数ということもあり避けたい 影響もこわい;; class <ロジックを追加するクラス> : public CLS_bbb ^^^^^^^^^^^^^^^^ サブクラスと継承の概念が誤っているかもしれません。 クラスの構成上継承できないということなのかもしれません。 当初と質問の内容が変わっており申し訳ないのですが ご教示いただければありがたいです。 質問を再度まとめますと 他のプロジェクトのヘッダファイルに定義されている変数 を使用したい その変数値はその時点における最新値を参照したい 変数の属性や型の変更は避けたい |
| この回答へのお礼 | この回答にお礼をつける(質問者のみ) |
回答 |
|
| ANo.6 | No.5 訂正です。 グローバル変数の管理のところ。 #if defined(GLOBAL_HERE) #define GLOBAL #define DEF(x) = (x) #else #define GLOBAL entern #define DEF(x) #endif です。 GLOBAL がひとつ抜けていました。 これで、 GLOBAL int iwork; GLOBAL int jwork DEF(1); と書かれた内容をインクルードすると以下のようになります。 #define GLOBAL_HERE #include "value.h" このとき、GLOBAL_HERE が定義されているので、 GLOBAL → (なにもなし) DEF(x) → = (x) と置換されます。 その結果、 int iwork; int jwork = (1); と展開されます。 #include "value.h" このとき、GLOBAL_HERE が定義されてないので、 GLOBAL → exntern DEF(x) → (なにもなし) と置換されます。 その結果、 extern int iwork; entern int jwork; と展開されます。 |
|---|---|
| 回答者:AsanoNagi | |
| 種類:アドバイス どんな人:一般人 自信:参考意見 |
|
| 回答日時: 08/05/16 12:34 |
|
| |
| この回答へのお礼 | この回答にお礼をつける(質問者のみ) |
回答 |
|
| ANo.5 | まず、2重インクルードの防止方法 これは、有名なテクニックです。 各インクルードファイルの先頭に #if !defined(HEAD_CHECK_AAA) #define HEAD_CHECK_AAA のような2行を入れます。 この、HEAD_CHECK_AAA は、2行で同じであり、他のヘッダファイルと重ならなければなんでもいいです。 そして、最後に #endif を入れます。 これで、同じファイルは実質的に1回しかインクルードされなくなります。 2番目。 まず、インクルードファイルの中で変数を定義しても、それは、単に、インクルードした場所にその記述がなされるだけです。 従って、インクルードファイルの中に int iwork; があったとしても、それを複数のふぃあるで別々にインクルードすると、それぞれ全く別の変数になります。 これを解決するためには、一緒にコンパイル(というか、本当はリンク)するファイルの1カ所で、 int iwork; と定義し、 その他の iwork を使いたい場所では、 extern int iwokr; という定義をします。 これは、変数の実体がどこにあるか、また、その変数をどこでいじっているかわかりにくくなるため、「グローバル変数の乱用」として、できれば避けるべきこととされています。 さて、上記のような事情ですが、 ・一カ所だけ変数定義 ・他の部分は extern をつける ・しかも宣言が異なっている(あるところは、 int あるところは char)とだめ というグローバル変数を統一的に管理する方法として、以下のようなテクニックがあります。 1)共通して読み込みヘッダファイルに以下のような記述をつけます。 たとえば、value.h とします。 #if defined(GLOBAL_HERE) #define GLOBAL #define DEF(x) = (x) #else #define entern #define DEF(x) #endif この後に、共通して使いたい変数を GLOBAL をつけて定義します。 GLOBAL int iwork; 初期値が必要な場合、 GLOBAL int jwoek DEF(1); のように書けます。 ここまでが、インクルードファイルの指定です。 あと、これを使うプログラムで、インクルードするわけですが、メインになるファイルだけ、 #define GLOBAL_HERE #include "value.h" のように、GLOBAL_HERE を define してからインクルードします。 それ以外のファイルでは、単純に(GLOBAL_HERE を定義せずに) #include "value.h" だけでインクルードします。 これで、 ・同じ型で ・一カ所だけ変数の定義があって ・他の部分は extern つき という宣言ができます。 しかも、もともとは、value.h というひとつのファイルなので、externつきとextern なしの変数の型が違っていたなんてこともありません。 |
|---|---|
| 回答者:AsanoNagi | |
| 種類:回答 どんな人:一般人 自信:参考意見 |
|
| 回答日時: 08/05/16 12:28 |
|
| |
| この回答へのお礼 | この回答にお礼をつける(質問者のみ) |
回答 |
|
| ANo.4 | /Pオプションを付けるなどして、プリプロセスだけを実行した結果を確認してみてください。 案外すぐに問題点が見つかるかもしれません。 |
|---|---|
| 回答者:jacta | |
| 種類:アドバイス どんな人:専門家 自信:参考意見 |
|
| 回答日時: 08/05/15 18:52 |
|
| |
| この回答へのお礼 | この回答にお礼をつける(質問者のみ) |
回答 |
|
| ANo.3 | とりあえず、「ミススペル」の可能性は当たってみた方が良いかもしれません。 または、aaa.h の中の、その部分だけ、コメントアウトされてしまっているとか、条件コンパイルで無視されるところにあるとか。 |
|---|---|
| 回答者:AsanoNagi | |
| 種類:アドバイス どんな人:一般人 自信:参考意見 |
|
| 回答日時: 08/05/15 18:01 |
|
| |
| この回答へのお礼 | 回答ありがとうございます。 >とりあえず、「ミススペル」の可能性は当たってみた方が良いかもしれません。 ミススペルは確認したところありませんでした。 >または、aaa.h の中の、その部分だけ、コメントアウトされてしまっているとか、条件コンパイルで無視されるところにあるとか。 前に回答してくださった方への補足に記載しましたが 新たにincludeファイルを追加する必要はなくなりましたが コンパイルエラーとなっております。 |
回答 |
|
| ANo.2 | まず、 #include "aaa.h" と書かれている直前と直後に aaa(; のように「絶対にエラーになる文」を挿入してコンパイルしてみよう。 もし aaa(; があるにも関わらず「対応する括弧が閉じていない」と言うエラーが出なかったとしたら #include "aaa.h" の行は「コンパイルされず無視される位置」に書かれている。書く位置を変えよう。 同様に、aaa.hの中で「使いたい変数を定義している行の前後」に、同じように「絶対にエラーになる文」を挿入してコンパイルしてみよう。 同じように「対応する括弧が閉じていない」と言うエラーが出なかったとしたら「変数を定義している行は、コンパイルされず無視される位置」に書かれている。書く位置を変えよう。 |
|---|---|
| 回答者:chie65536 | |
| 種類:回答 どんな人:一般人 自信:参考意見 |
|
| 回答日時: 08/05/15 17:27 |
|
| |
| この回答への補足 | 意見参考になりました。 ありがとうございます。 その後調査を進めたところ、既設のソースにて 該当includeファイルは読み込まれおり、2重定義を していました。 ネストがあったため気づきませんでした。 前の方の回答の補足に記載しましたが、 では単純に直接変数名を指定して使用する ということではないようです。 お教え頂けるとありがたく思います。 |
| この回答へのお礼 | この回答にお礼をつける(質問者のみ) |
回答良回答10pt |
|
| ANo.1 | そのincludeファイルの中で他のincludeの内容が関わる物が有るんじゃない? もしそうだとしたらincludeの順番とかでも出る出ないが変わるよ |
|---|---|
| 回答者:SAYKA | |
| 種類:アドバイス どんな人:一般人 自信:参考意見 |
|
| 回答日時: 08/05/15 17:20 |
|
| |
| この回答への補足 | 意見参考になりました。 ありがとうございます。 その後調査を進めたところ、既設のソースにて 該当includeファイルは読み込まれおり、2重定義を していました。 ネストがあったため気づきませんでした。 しかし再度コンパイルしたところ、同じエラーが発生しております。 これについて2点疑問に思いました。 1点目 "aaa.h"の中で"bbb.h"を読み込んでおりさらに"bbb.h"の中で "ccc.h"を読み込んでいる場合において"ccc.h"内で定義されている 変数を使用したい場合"aaa.h"だけをプログラムで読み込んで、 直接変数名を指定して使用することは可能なのでしょうか (各ヘッダファイルの場所はプロジェクトが異なっていたりします) ccc.h内の定義 int iwork; プログラム #include "aaa.h" ------------------- iwork = 2; ------------------- 2点目 他のプロジェクトで変数に値をセットしていて、 その変数値を参照する場合、includeファイルを読み込んで その変数を参照しても値はとれないように思えてきました。 よくわかっていない部分なのですが、クラス変数の引継ぎが 必要のように思います。 イメージ的にはもともと変数値をセットするところをたどって そのクラスから今回ロジックを追加するクラスまで変数を引き継ぐ ということなのですが、どうコーディングしていいか分かって おりません。 2点目については最初の質問から外れているかもしれませんが 宜しくお願い致します。 同一問題なのかわかっておりません。 |
| この回答へのお礼 | この回答にお礼をつける(質問者のみ) |