クラスの継承について

[戻る]
Fortran使い 2005/08/08(月) 10:59:25
こんにちはFortran使いです。VC++(6.0)についての質問です。
私はMDIソフトでいくつかのViewの切り替えのできるソフトを作成しようと思っていま
す。その第1歩としてViewクラスの派生クラスを作ろうとしています。(アプリケーシ
ョンウィザードで生成されたCXXXViewクラスの継承)
挿入>クラスの新規作成 から作成してコンパイルすると以下のようなエラーが出ま
す。
c:\vc\mditest\mditestview.h(21) : error C2143: 構文エラー : ';' が '*' の前に必要
です。
c:\vc\mditest\mditestview.h(21) : error C2501: 'CMDItestDoc' : 識別名を宣言する
のに、型が指定されていません。
c:\vc\mditest\mditestview.h(21) : error C2501: 'GetDocument' : 識別名を宣言する
のに、型が指定されていません。

このmditestview.hはアプリケーションウィザードで生成されたViewクラスで派生元で
す。


エラーの発生場所は以下のところです。
// Attributes
public:
    CMDItestDoc* GetDocument();

クラスを派生させただけでDocumentTemplateにも登録しておらず実際のコンパイル作業
には全然影響ないような気もするのですがエラーが出ます。

間違えてどこかいじったのではと思い作成した派生クラスを削除してみると問題なくコ
ンパイルできています。

作成された派生クラスをみてもコンストラクタとデストラクタぐらいの記述しかなく構
文としては問題ないように見えます。(MFC特有の現象でしょうか?)

初歩の初歩かもしれませんが、なぜこのようなことが起こるのか、対策としては何をす
ればよいのかを教えてください。

よろしくお願いします。

tib 2005/08/08(月) 11:13:46
「CMDItestDoc」がなんのこっちゃわからん。...というエラーです。

コンパイラは当該部分より前でCMDItestDocがクラスである事を知らなくてはなりませ
ん。CMDItestDocの定義はどこで行われていますか? mditestview.hとは違う、別の.hファ
イルですか? ならば、mditestview.hの当該部分以前(通常ファイルの先頭)で、

・mditestview.h で、CMDItestDocの定義をしているファイルをインクルードする。
・mditestview.h 内でCMDItestDocのメンバ変数・メンバ関数にアクセスしないなら、
 −インクルードの代わりに「class CMDItestDoc;」という1行を追加する。
 −mditestview.cppでCMDItestDocの定義をしているファイルをインクルードする。

どちらか状況に合った方をお試してみてください。

Fortran使い 2005/08/08(月) 12:09:16
tibさんありがとうございます。
ご指摘、的中のようです。
mditestview.h内でmditestdoc.hをインクルードしてみました。(ヘッダーファイル内で
ほかのヘッダーファイルをインクルードしたのは初めてです。正直気持ち悪いです。)
これで問題なくコンパイルできています。

これで解決としたいのですが、なぜこのようなことが起こるのかとご指導いただければ
ありがたいと思います。はじめの文では伝わりにくかったようなので再現性のある形で
説明させていただきます。

アプリケーションウィザードでMDIアプリケーション(設定はデフォルト)のスケルトン
を作成します。アプリ名はmditestとしてあるので上記のようなファイルが生成されてい
ます。この状態では当然整合性は取れていて上のようなエラーは出ません。(もちろん
mditestview.h内でCMDItestDocの記述は上記のとおりです。)

CMditestViewクラスから派生クラスを作ります。(挿入>新規クラス)
ここでコンパイルするとエラーが発生します。
このエラーはtibさんの指摘どおりCMDItestDocが認識できないためのエラーです。
しかし、派生クラスは実装していないので影響があるのが不思議でなりません。

VC++では同じクラスをいくつかに派生させて機能を振り分けるということは日常的に
なされていると思います。このようなことはありうるのでしょうか?

実質的には解決しているのですがあと少しご助力お願いします。

KING・王 2005/08/08(月) 13:09:55

> これで解決としたいのですが、なぜこのようなことが起こるのかとご指導いただければ
ありがたいと思います。

tibさんが、次のように説明されています。

> コンパイラは当該部分より前でCMDItestDocがクラスである事を知らなくてはなりません。

おそらく、Fortran使いさんが提示されているコンパイルエラーが発生しているのは、
mditestview.cppファイルをコンパイルしているときに発生しているのではないでしょうか?

c/c++のコンパイルは、基本的に.c/.cppファイル単位で行われます。
その際に、includeされているファイルは、includeされるので、その内容を参照可能ですが、
他のincludeされていない.hファイルや、他の.c/.cppファイルの内容は参照できません。

ここで、おそらくmditestview.cppの中で、mditestview.hがincludeされていますが、
その中にでてくるCMDItestDocに関しては、CMDItestDoc.hをincludeしていないと、
CMDItestDocとは変数名なのか、クラス名なのかなどが、コンパイラには分からない為、
上記のようにエラーとなっているのです。

>(ヘッダーファイル内でほかのヘッダーファイルをインクルードしたのは初めてです。正直気
持ち悪いです。)

別に、mditestview.cppの中で次のような記述でもOKだと思います。

---- mditestview.cpp ----
#include "CMDItestDoc.h"
#include "mditestview.h"
(後略)
---- ここまで ----

※上記の記述では、includeする順番が重要です。

#mditestview.cppが違う名前のファイルの可能性もあります。
#その場合は、ファイル名を適当に読みかえてください。

#識者の方、説明に不備があるようでしたら、フォローをお願いします。

Fortran使い 2005/08/08(月) 13:56:01
皆さんありがとうございます。
KING・王さんmditestview.cppの中でのインクルードがカッコとしてもいいのかとは思い
ます。
MDItestDoc.hをインクルードしないとCMDItestDocをコンパイラが認識できないというの
も理屈としても実体験としても理解できたところです。

しかし、生成されたスケルトンとしては正常にコンパイルできるものがひとつのクラス
を継承(しかも実装していない)しただけで余分にヘッダーファイルをインクルードし
なければならないのは釈然としません。何か重要な部分を見落としているような気がし
ています。

ご存知の方や理解はしていないが同じ経験をした方はアドバイスください。
よろしくお願いします。

dairygoods 2005/08/08(月) 14:47:23
> しかし、生成されたスケルトンとしては正常にコンパイルできるものがひとつのクラス
> を継承(しかも実装していない)しただけで余分にヘッダーファイルをインクルードし
> なければならないのは釈然としません。

とあるヘッダーファイルを使うときに、同時に必要となるヘッダーを
各.cppファイルでインクルードするというスタイル(MFC流)をとる限り、
この現象は避けられないでしょう。

ちなみに、「実装していない」わけではありません。
継承しただけで、継承元のクラスが実装していた内容を、
派生クラスが、丸ごと受け継いで実装したことになります。

Fortran使い 2005/08/08(月) 15:00:59
やはりおかしいです。
MDItestView.cppでは
#include "MDItestDoc.h"
#include "MDItestView.h"
の順にスケルトンが生成されてますので問題ないと思います。

次に二つのファイルをプロジェクトに追加すると
// InputGraphView.h: CInputGraphView クラスのインターフェイス
//
//////////////////////////////////////////////////////////////////////

#if !defined
(AFX_INPUTGRAPHVIEW_H__1B944FFF_EF77_4135_AC68_254AB940D813__INCLUDED_)
#define AFX_INPUTGRAPHVIEW_H__1B944FFF_EF77_4135_AC68_254AB940D813__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "MDItestView.h"

class CInputGraphView : public CMDItestView  
{
public:
    CInputGraphView();
    virtual ~CInputGraphView();

};

#endif // !defined
(AFX_INPUTGRAPHVIEW_H__1B944FFF_EF77_4135_AC68_254AB940D813__INCLUDED_)

// InputGraphView.cpp: CInputGraphView クラスのインプリメンテーション
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "MDItest.h"
#include "InputGraphView.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// 構築/消滅
//////////////////////////////////////////////////////////////////////

CInputGraphView::CInputGraphView()
{

}

CInputGraphView::~CInputGraphView()
{

}

これらを追加すると先ほどのエラーが出ます。
このときも
MDItestView.cppでは
#include "MDItestDoc.h"
#include "MDItestView.h"
ここは変更していないのでCMDItestDocの定義は文法上は問題ないのですがエラーになり
ます。
ここでtibさんのヒントからMDItestView.h内で#include "MDItestDoc.h"
をするとエラーが解消されます。
問題が整理されていくほど不思議でなりません。

そこで疑問点は2つに整理できると思います。

○MDItestView.cppでは
#include "MDItestDoc.h"
#include "MDItestView.h"
とされ順番どおり宣言されているので問題はないはずであるのに
MDItestView.h内で#include "MDItestDoc.h"という変則的な手段で解決される
問題が発生すること。

○元のクラスを書き換えないで派生させているだけなのに元のクラスの挙動が変わって
いるらしいこと。

以上の点よろしくお願いします。

Fortran使い 2005/08/08(月) 15:11:51
dairygoodsさんご意見ありがとうございます。
入れ違いになってしまったようですが、cppが必要なファイルをインクルードするという
話ですが上にまとめました通り必要なヘッダーファイルのインクルードのしかたが変則
的になっています。

実装の件は私の勉強不足だったかもしれません。スケルトンではCMDItestViewクラスが
DocumentTemplateに渡されています。これの派生クラス(私が作った)CInputGraphView
クラスはまだDocumentTemplateクラスに登録させては居らずインスタンスが生成されて
いないため実装されていないと考えていました。

CMDItestViewからCInputGraphViewを派生させた時点で実装(具体的なイメージがわきま
せんが)扱いになっているのであれば悪さしてもおかしくないのかとは思いますが。

ご教授よろしくお願いします。

dairygoods 2005/08/08(月) 15:24:47
ある.cppファイルでちゃんとインクルードされていると言う事実は、
別の.cppファイルのコンパイルには、何の影響もありません。

あるクラスを継承してコンパイルするときに、
継承元のクラスのコンパイルが上手くいっているという
事実も全く関係ありません。

#include というのは、そのインクルードファイルに書かれた
クラスのコンパイル結果を取り込むというような、
高度な動作をするものではありません。
そのincludeしたファイルに書かれた内容を、
その部分にコピー&ペーストしたのと同じ効果しかありません。

つまり、CInputGraphView.cpp をコンパイルするときは、
CInputGraphView.cpp に書かれた #include 文を、
そのファイルの中身と置き換え(さらに、再帰的に#includeを置き換え)て、
完成した1個のテキストだけを元にコンパイルされるのです。

Fortran使い 2005/08/08(月) 16:00:30
[[解決]]
daurygoodsさんありがとうございました。
アドバイスをじっくり見ながらいろいろ見渡してみました。

CInputGraphViewは組み込んでないので生成されていないとの
先入観があったので見落としていました。

結論としてはCInputGraphView.cppに
#include "MDItestDoc.h"
がなかったためでした。

MDItestView.hでエラーが起こっていたためMDItestView.cppがらみだと決めてかかって
いました。マイクロソフトさんももうちょっと気の利いたツールを作ってくれればとお
もうのですが。(同じドキュメントとセットにするとは限らないのでわざとそうしてい
るのかもしれませんが)

皆さんありがとうございました。

PATIO 2005/08/08(月) 16:20:03
既に解決になっていますが、
IDEのウィザード機能に期待し過ぎない方が良いと思います。
ウィザード機能はあくまでも作業の省力化が目的であってC++の基本的な知識がなくても
C++のプログラミングを出来るようにするための物ではないと思います。
便利な道具は道具として使う事に関しては問題ないと思いますが、
これらの道具が無くてもプログラミングが問題なく出来るくらいの言語知識を持っている
事が前提となると思います。
今回の件に関してもVCだからという事ではなくてC++やC言語で組んでいれば、
普通に遭遇するような問題です。
言語知識の習得が必要だと思いますよ。

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