どうかよろしくお願いします。
■やりたい事
・基底クラスCBaseを継承した、派生クラス複数種類 CSub1~CSubNを、
それぞれの型のポインタの、オブジェクトの動的な生成に応じてサイズの変わる可変長の配列のような物で管理したい。(下記ソースではstd::listを使っています)
・その可変長の配列のような物のポインタを引数に取り、CBaseが持つ、もしくはオーバーライドされたメンバ関数を呼び出す関数を作りたい。
■避けたい事
・派生クラス複数種類 CSub1~CSubNを,CBase*型で管理する事。
・可変長でない方法(例えば普通の配列 CSub1* s1List[MAX_ARRAY]; 等)で管理する事。
・関数を呼び出す前に、引数として扱う為のCBase*型のリストを用意する事。
#include <iostream>
#include <list>
using namespace std;
// 基底クラス
class CBase
{
public:
virtual void m_Func(){
cout << "CBase" << endl;
}
};
// 派生クラス
class CSub1 : public CBase
{
public:
void m_Func(){
cout << "CSub1" << endl;
}
};
// CBaseとは無関係のクラス
class COther
{
public:
void Func(){
return;
}
};
// クラスのポインタを引数にする関数
void func1(CBase* pCBase)
{
pCBase->m_Func();
}
// クラスのポインタのlistのポインタを引数にする関数
void func2(list<CBase*>* pCBaseList)
{
(*pCBaseList->begin())->m_Func();
}
// listをひとまずvoid*で受け取る関数
void func3(void* list)
{
(*((std::list<CBase*>*)list)->begin())->m_Func(); // キャストしてメンバ関数を呼び出す
}
int main(){
// オブジェクトとポインタ変数の準備
CBase* oBase = new CBase;
CSub1* oSub1 = new CSub1;
// listの準備
list<CBase*> baList;
list<CSub1*> s1List;
baList.push_back( oBase );
s1List.push_back( oSub1 );
// クラスのポインタを引数にする関数を呼び出す
func1( oBase );
func1( oSub1 ); // アップキャストが行われる
cout << endl;
// クラスのポインタのlistのポインタを引数にする関数を呼び出す
func2( &baList );
// func2( &s1List ); // この行は引数の型が合わずにエラー
cout << endl;
// listをひとまずvoid*で受け取る関数を呼び出す
func3( &baList );
func3( &s1List ); // 成功
cout << endl;
// でも……
// CBaseを継承しないクラスのリストをfunc3()に渡したりすると……
COther* oOther = new COther;
std::list<COther*> otList;
otList.push_back( oOther );
// func3( &otList ); // 実行時にアクセス違反
return 0;
}
CBase
CSub1
CBase
CBase
CSub1
////////////////////////
■問題点 と です。
前者は引数として渡せないので、期待通りの動作になりません。
後者は一応は期待通りの動作はするのですが、ミスがあった場合にビルド時には発見できないバグが潜んでしまいます。
説明の順序が逆になってしまったかもしれませんが、
クラスCBaseは、「funcNが引数に取れるクラス」の基底クラスにしたいのです。
最初はfunc1()のようにアップキャストが行われ、上手くいきそうでした。
しかし、ポインタをlistで管理しようとしたとたん、上手くいかなくなりました。
いずれは、funcN(char str[]);やfuncN(int* value);などでオーバーロードし、何種類かの変数にも対応させたいと思っています。
■どうしたら解決できるか
・func1()とfunc2()を合わせたような具合に、list<CSub1*>*型をlist<CBase*>*型にキャストできれば解決。
・func3()で実行時にアクセス違反が起こるようなキャストを行った場合、ビルド時にエラーが発生するようにできれば解決。
どちらか一方でも解決ですが、可能なのでしょうか?
その他にも何か別の方法や基本的な事を見落としているかも知れないです。
何か気付いた事がありましたら指摘してください。