お世話になります。
■概要
VC++/MFCで、ダイアログベースのアプリケーションを作成しています。
アプリケーションはダイアログを複数持ち、ダイアログごとに扱うデータの種類が異な
ります。
([ダイアログ1]では社員一覧、[ダイアログ2]では部署一覧、のような感じです。)
このため、それぞれのダイアログで扱うデータ一式をひとつのクラスとして定義し、ク
ラス群をアプリケーションクラスで一元管理したいと考えています。
(アプリケーション起動時にデータクラスをすべてインスタンス化し、アプリケーショ
ン実行中はそのインスタンスを使い続け、アプリケーション終了時にメモリを開放?す
るようなイメージでいます。)
技術的には、このような設計は可能だと思っていますが、具体的な実装方法、コーディ
ング方法がわかりません。
質問したいのは、以下2点です。
1.「データクラス」のインスタンス化処理および変数の初期化処理は、
アプリケーションクラス(CXXApp)のどこに記述すればよいのでしょうか。
--------------------------------------------------------------------
【現状】
CXXAppのメンバ変数として
public:
CXXDlgData dlgdata;
のように宣言していますが、コンパイル時に以下のエラーが出ます。
error C2146: 構文エラー : ';' が、識別子 'dlgdata' の前に必要です
error C4430: 型指定子がありません - int と仮定しました。
メモ: C++ は int を既定値としてサポートしていません
--------------------------------------------------------------------
2.アプリケーションクラス(CXXApp)でインスタンス化処理した「データクラス」
のデータや処理をダイアログのクラスから使いたい場合、どのような方法で
アクセスすればよいのでしょうか。
C++のオブジェクト志向については、入門書レベルの書籍でひととおり学んだつもりでお
りますが、MFCのアーキテクチャの中でこのような自前の「データクラス」を使う方法が
わかるほどには理解できていない状態です。
■補足
アプリケーションは以下のようなダイアログ及びクラスで構成されています。
【ダイアログ(リソース)】
IDD_CXX_DIALOG:アプリケーション起動時に最初に表示するダイアログ。
IDD_CXX_DIALOG2:IDD_CXX_DIALOGからのボタンクリックにより起動するダイアログ。
【クラス一覧】
CXXApp:アプリケーションクラス
CXXDlg:IDD_CXX_DIALOGに関する処理を定義するクラス。
CXXDlg2:IDD_CXX_DIALOG2に関する処理を定義するクラス。
CXXDlgData:CXXDlgクラスにて扱うデータ一式を持つデータクラス。
CXXDloData2:CXXDlg2クラスにて扱うデータ一式を持つデータクラス。
非常に初歩的な質問となり恥ずかしいのですが、よろしくお願いいたします。
CXXDlgDataのヘッダを#includeしてないだけのことじゃないかと推測されます。
> επιστημη様
アドバイスありがとうございます。
ヘッダのincludeを確認したところ、ご指摘のとおりでした。
クラスのインスタンス化を記述している行よりも後にincludeがあったことが原因でし
た。ケアレスミスの範疇ですね。大変失礼いたしました。
上記問題点のうち、ひとつ目は解決しました。ありがとうございます。
以下の問題については、依然として解決しないままになっております。
2.アプリケーションクラス(CXXApp)でインスタンス化処理した「データクラス」
のデータや処理をダイアログのクラスから使いたい場合、どのような方法で
アクセスすればよいのでしょうか。
--------------------------------------------------------------------
【現状】
・CXXDlgクラス内にて、CXXDlgDataクラスのデータ(例:CString str)を
取得したい。
・CXXDlgDataクラスは、アプリケーションクラス(CXXApp)のメンバ変数として
インスタンス化している。
--------------------------------------------------------------------
■CXXDlgDataクラスのヘッダ
#pragma once
class CXXDlgData : public CObject
{
public:
CXXDlgData(); // コンストラクタ
virtual ~CXXDlgData(); // デストラクタ
private:
CString str; // メンバ変数
public:
CString Getstr(){
return str; // データ取得用アクセス関数
}
}
■CXXDlgDataクラスの実装
#include stdafx.h
#include CXXApp.h
#include CXXDlgData.h
// コンストラクタ
CXXDlgData::CXXDlgData()
{
str=あああ;
}
// デストラクタ
CXXDlgData::~CXXDlgData()
{
}
--------------------------------------------------------------------
この状態で、ダイアログに関する処理を定義しているクラス「CXXDlg」内で
CXXDlgDataクラスのインスタンス「dlgdata」に属するメンバ変数「str」を
取得するには、どうすればよいのでしょうか?
以下のように記述してみましたが、エラーとなります。
error C2228: '.str' の左側はクラス、構造体、共用体でなければなりません
--------------------------------------------------------------------
■CXXDlgクラス内での記述(エラーとなる)
AfxMessageBox(CXXApp::dlgdata.str);
--------------------------------------------------------------------
すみませんが、よろしくお願いいたします。
直接参照するのではなく、dlgdataをDoModal()でポインタで渡すなり、メンバ関数で
セットしてやるなりするべきと思われます。
#AfxGetApp()->dlgdata.str
#という反則技もありますけど・・・
> PSB様
ご助言ありがとうございます。
「直接参照するのではなく」というご意見からヒントを得て、いろいろと試してみまし
た。
現在のところ、以下の方法でとりあえず解決の兆しです。
(アプリケーションクラス「CXXApp」でのデータクラス「dlgdata」のインスタンス
生成方法を変更し、externとしました。)
しかしながら、アプリケーションのつくりとしてOKなのか?
ナンセンスな事をしているのではないか?
という疑問が残ります。
また、現在作っているアプリケーションは、ダイアログが全部で50近くあり、
データクラスの数も同様で50近くとなる見込みです。
この方法で、パフォーマンスはどうなのか?等がちょっと心配です。
従いまして、まだ「解決」ステータスにはせずにおかせてください。
もう少し良い方法はないか、自分でも調べて見ます。
また、どなたか下記方法が変ではないかどうかご判断していただけますと大変有難いで
す。
--------------------------------------------------------------------
【現状】
とりあえず以下の方法で動作しています。
--------------------------------------------------------------------
■CXXAppクラスのヘッダ
クラスのインスタンス生成の方法を変更。
クラスの定義外に以下の記述をしました。
extern CXXDlgData dlgdata;
■CXXAppクラスの実装
以下の一文を追加しました。
CXXDlgData dlgdata;
--------------------------------------------------------------------
■CXXDlgDataクラスの実装
以下のように修正しました。
(コンストラクタによる値の初期化方法を変更。これはあまり関係ないかも)
#include stdafx.h
#include CXXApp.h
#include CXXDlgData.h
// コンストラクタ
CXXDlgData::CXXDlgData()
:str(あああ)
{
}
// デストラクタ
CXXDlgData::~CXXDlgData()
{
}
--------------------------------------------------------------------
■CXXDlgクラス内での記述(エラーにはならず、値の取得可能!)
AfxMessageBox(dlgdata.Getstr());
--------------------------------------------------------------------
XXXDlg と XXXDlgData とが密接に関係しているなら、
XXXDlgDataをXXXDlgに渡してダイアログに書き換えてもらうことにすれば、
利用者はXXXDlgとのインタフェースを意識せんでええようになりますな。
XXXDlg : public CDialog {
XXXDlgData* data;
// - OnInitDialogあたりで*dataに基づいて
// コントロールを変更する
// - DialogのOKが押されたら、コントロールの状態に基づいて
// *dataを書き換える
public:
XXXDlg(XXXDlgData* target) : data(target), ...
};
とかやっとけば利用者側では:
XXXDlg dlg(AfxGetApp()->XXXdata);
dlg.DoModal();
> επιστημη様
なるほど!
そういう方法がありますね。
データとダイアログを分離する目的で、ダイアログとデータクラスを一対一対応で作成
しているので、こちらの方法も検討してみます。
とりあえず、目的とする機能は実現できましたので、「解決」とさせていただきます。
皆様ありがとうございました。
ステータスを「解決」とするのを忘れていました。
大変失礼いたしました。