• 締切済み

仮想関数名をすり替える。

こんばんわ。 意味不明なタイトルで申し訳ありません。 ライブラリAからライブラリBへの切り替えの仕事を請け負いました。 可能な限りソースコードはいじらないでほしいということで困っています。 メンバー関数は互換性があるので問題ないとのことでした。 以下のような基底クラスと派生クラスがあったとします。 class A を class B に切り換えたいとのことです。 ----------------------- class A { virtual create() ; } ----------------------- class B { virtual Create() ; } class C : public A { virtual create() ; } まず class C の派生元を以下のように typedef B A ; と記述した共通ヘッダーを用意して class C にincludeしてすり替えることができました。 ところが困ったのがcreate関数で関数名の先頭文字がライブラリAが小文字で、ライブラリBが大文字になっていました。 これをうまくすり替えたいのですが手段が思いつきません。class C 側に #ifdef _NEWLIB virtual Create() ; #else virtual create() ; #endif 記述するしか思いつきませんでした。ただ問題は class A から派生しているクラスが結構あるのですべてにifdef ディレクティブを記述するのは結構な作業なのと、なにより記述ミスが怖いです。 何か良い手段はないものでしょうか?

みんなの回答

  • hitomura
  • ベストアンサー率48% (325/664)
回答No.3

どうもすみません、回答 #2 の中に恥ずかしいミスがありました。 #ifndef _NEWLIB は #ifdef _NEWLIB の間違いです。 上記間違いのままだと、新しいライブラリ B を使うために _NEWLIB を付けると古いライブラリ A を参照し、前のを使おうと _NEWLIB 無しにすると新しい方を使うという正反対の結果となってしまいました。 お手数をおかけして申し訳ありませんでした。

TeijigoTeatime
質問者

お礼

早々のご返答ありがとうございます。 質問はできるだけ伝わりやいように書いたつもりでした。 サンプルも提示していただき助かります。 これを元に発注者に相談します。

  • hitomura
  • ベストアンサー率48% (325/664)
回答No.2

……っと、いかん、#1の回答では何をやっているのか解りづらかったですね。では改めてサンプルコードを記載します。 #ifndef _NEWLIB class D { virtual create() { base.Create(); } private: B base; } typedef D A; #endif 要するに、B での処理を呼び出すだけの A での名前と同じメンバ関数を持つクラスを間にかませてやればいいだけですね。 ……あ、ひょっとして新しいライブラリでもライブラリの使用には B から派生させないといけませんか? ならば、D の定義を class D : public B { virtual create() { this.Create(); } } としてください。

  • hitomura
  • ベストアンサー率48% (325/664)
回答No.1

つ Adapter パターン http://ja.wikipedia.org/wiki/Adapter_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3 create() の宣言がこのままだとコンパイル通らないとおもうんだけど、とりあえずそこはそのままで以下の通りでいける、と思う。 class D { virtual create() { #ifdef _NEWLIB base.Create(); #else base.create(); #endif } private: #ifdef _NEWLIB B base; #else A base; #endif } #ifndef _NEWLIB typedef D A; #endif

関連するQ&A

  • 仮想関数について困っています

    仮想関数について困っています C++を現在勉強中でその中で困ったことができました。 仮想関数についてまだ分かっていないことが多いのですが、一応以下のように使うものだと学びました。 class test{  public:   virtual void run(){    std::cout<<"testクラス"<<std::endl;   } }; class test_sub:public test{  public:   void run(){    std::cout<<"test_subクラス"<<std::endl;   } }; int main(){  test *t_s;  t_s=new test_sub;  t_s->run(); } ※includeは省略させていただきます こうすれば「test_subクラス」と出力されるはずです。 そこで本題なのですが自作のarrayクラスのようなものはテンプレートクラスになっているのですが array<test*> data; data[0].run(); のように使うと「testクラス」と表示されてしまいます。 これを解決する方法は何かないでしょうか? ご存じの方がいましたら教えていただけると助かります。

  • 個々の関数について継承しているかどうかを判定したいんですが、

    個々の関数について継承しているかどうかを判定したいんですが、 class CBase {public: virtual int A(){return 0;} virtual int B(){return 0;} }; これが規定クラスだとして、 class CTest : public CBase {public: int A(){return 1;} int B(){return 1;} }; のクラスが存在します。 一番有効だと思ってるのが、上記を変えて CBase :: virtual int A(){throw this_base; return 0;} のように書けば判定できると思いますが、例外を使うよりもいい方法はありませんか。

  • 可変長引数をもつオーバライド関数について

    オーバライド関数について質問があります。 以下のようなクラスAとBがあります。 クラスAは基本クラスです。 クラスBはクラスAから導出しました。 ------------------------------------ CLASS A { public: virtual void func(char* p, ...); } ------------------------------------ CLASS B : public A { public: void func(char* p, ...); } ------------------------------------ メンバ関数の func() はオーバライド関数で、可変長の引数を持っています。 今、クラスBの func() の中で、クラスAの func() をコールするようにコーディングしました。 ----------------------------------- void B::func(char* p, ...) { : : A::func( ???? ) : : } ----------------------------------- ところが、クラスBの func()が受け取った引数を、そのままクラスAの func() に渡したいのですが、どうしたらいいのか分かりません。これって無理でしょうか? 教えて下さい。

  • [C++/CLI] アンマネージクラスの中でマネージクラスを使用したい。

    イベント駆動型のライブラリを使用しているプログラムのC++/CLIへの移行で困っています。 イベントの基底クラスAがC++の構文で書かれているため、派生クラスBはclassで宣言するようにコンパイラからエラーが帰りました。 ですので、classと宣言すると今度はアンマネージクラスの中でマネージコードは使用不可能といわれました。 どうにかこの現象を回避する方法はありませんか? class A : ライブラリで宣言されているイベントハンドラ(変更不可能) ref class B : A{} と宣言するとref classは使えないとエラー class B : A{} と宣言するとマネージコードが使用できないとエラー

  • 基本クラスのポインタで、派生クラスのメンバ関数を呼び出す方法?

    VC++でプログラミングをしています。 A(基本クラス) B(派生クラス) を作成しました。Bは、Aの特別な場合です。 このとき、基本クラスAのポインタから、派生クラスBにのみあるメンバ関数を呼ぶことはできないのでしょうか? 基本クラスAにも同じ名前の関数があれば、仮想関数をオーバーロードすれば呼び出せるようですが、この関数は、基本クラスには不要なので、できれば使わないメンバ関数を基本クラスに書きたくありません。 (純粋仮想関数という方法もあるようですが、) 操作としましては、 Aのポインタ配列 A* a[100]を作成し 特別な場合のみ派生クラスBのメンバ関数だけを実行させたいのです。 派生クラスにのみあるメンバ関数を、Readとします。 for(i=0;i<100;i++){ if(派生クラスBの場合){ a[i]->Read() } } 現状では、コンパイルエラーで、 関数Readは、aのメンバ関数ではありませんとなってしまいます。 以上よろしくお願いします。

  • 仮想関数と継承について

    #include <iostream> using namespace std; class AAA { public: virtual aaa() { cout <<"aaa(void)"<<endl;} }; class BBB : public AAA { public: virtual aaa(int a) { cout <<"aaa(int)"<<a<<endl;} }; int main() { BBB bbb; bbb.aaa();<--これがエラーになります。 return 0; } どうして、既定クラスの引数なしのaaa()はよぶことが できないのでしょうか?

  • c++,ある関数のクラスから別のクラスの関数を呼ぶ

    c++で、あるクラスのメンバ関数から、別のクラスのメンバ関すを呼びたいのですが、どのようにしたらできますか? 例えば、以下のような単純なコードを考えています。やりたいことは、Aのメンバ関数であるaaa()からBのクラスであるbbb()を呼びたいと思っています。その理由を少し説明します。ここでは、Aというクラスとmain関数はオープンソースコードを例えています。できるだけ、元のオープンソースコードを書き換えずに新たな機能を拡張したいと思っています。そこで、Bというクラスを使って、元のオープンソースコードに機能を拡張しようとしています。このような理由なので、bbb()という関数はaaa()という関数から呼びたいです。メイン関数には何も書き加えないのがベストです。 現状では、実行すると「this is aaa」という出力しか出ません。ここに「this is bbb」の出力を加えたいです。クラスAとBにある程度コマンドを追加して、解決できないでしょうか。 #include <iostream> using namespace std; //------------------------------------------------------ class A{ public: void aaa(); virtual void bbb(){} }; //------------------------------------------------------ //------------------------------------------------------ class B : public A{ public: void bbb(); }; //------------------------------------------------------ //------------------------------------------------------ void A::aaa() { cout << "this is aaa \n"; bbb(); } //------------------------------------------------------ //------------------------------------------------------ void B::bbb() { cout << "this is bbb \n"; } //------------------------------------------------------ //------------------------------------------------------ int main() { A a; a.aaa(); return 0; } //------------------------------------------------------

  • 仮想基底クラスをもつクラスの代入演算

    仮想基底クラスをもつクラスの代入演算で、仮想基底クラスの代入が各々のサブオブジェクトにつきただ一回なされるようにしたい場合に、みなさん、どのように設計されていますか? 何か、手軽なテクニックがあれば、ご教示ください。 ===(コンストラクタなどは略、アクセス制御も略) たとえば、 struct X { int x; }; struct A : virtual X { int a; }; struct B : virtual X { int b; }; struct C : A, B { int c; }; int main() { C c1, c2; c1 = c2; } として、デフォルト代入に頼ると、c1.x への c2.x の代入を複数回行うコンパイラが多いですよね(というか、きっちり1回のみ行うようにしているコンパイラに出会ったことがない)。C++標準でも、初期化はただ一度とコンパイラが保証するようになっていますが、代入は何度代入してもいいようになっていたと思います。 以下のように、各クラスで、直接の非仮想基底クラスと自身のデータメンバにのみ代入するメンバ関数を定義して、最派生クラスでのみ、仮想基底クラスの代入を行うのが、普通のやり方なんでしょうか。 これでもいいのですが、後に、ある基底クラスに仮想クラスが付け加わったりすると、その基底クラスから派生しているクラスの代入演算の定義をすべていじらないといけなくなるので、もっといいテクニックがあるのなら、と思いまして質問したしだいです。 struct X { int x; X &nvAssign(const X &z) { x = z.x; return *this; } X &operator=(const X &z) { nvAssign(z); } }; struct A : virtual X { int a; A &nvAssign(const A &z) { a = z.a; return *this; } A &operator=(const A &z) { X::nvAssign(z); return nvAssign(z); } }; struct B : virtual X { int b; B &nvAssign(const B &z) { b = z.b; return *this; } B &operator=(const B &z) { X::nvAssign(z); return nvAssign(z); } }; struct C : A, B { int c; C &nvAssign(const C &z) { A::nvAssign(z); B::nvAssign(z); c = z.c; return *this; } C &operator=(const C &z) { X::nvAssign(z); return nvAssign(z); } }; === 1. 仮想基底クラスは何度代入されてもいいようにするもんだ。 2. 仮想基底クラスにデータメンバを持たせるのは間違いだ。 3. 遅くなるから、そもそも仮想基底クラスなど使わない。 という回答は無しでお願いいたします。たぶん、1 か 2 が正解なんでしょうけど^^

  • 関数ポインタにvirtual関数を与えたいです

    //関数ポインタについて質問させてください。 //error C2440: '=' : 'void (__thiscall A::* )(int,int)' から 'void (__cdecl *)(int,int)' に変換できません。 //というエラーが出ます。 //どうすればいいのか教えてください。 //よろしくお願いします。 #include<stdio.h> class A { public: void (*aaa)(int a,int b); virtual void test(int a,int b)=0; virtual void test2(int a,int b)=0; void execute() { aaa=test;//error C2440 } }; class B : public A { public: void test(int a,int b) { printf("test"); } void test2(int a,int b) { printf("test2"); } }; int main() { B b; b.execute(); b.aaa(2,3); return 0; }

  • C言語のライブラリで"A"を20文字生成する関数名を知りたいです。

    C言語のライブラリで"A"を20文字生成する関数名を知りたいです。 C言語やVBなどのプログラミングで良く関数やライブラリとして存在している名前を調べる良いサイトを知っている方はいらっしゃいますか?