2009-06-29 18 views
1

汎用性のある関数を呼び出す方法は想像できません。私は、異なる瞬間に2つの異なるクラスで関数を呼び出さなければならないコードを持っています。同じ関数内で異なる時間に異なるクラスを呼び出す

私は1回または他の時間にアクセスできるAクラスとBクラスを持っています。または、私はAまたはBにアクセスします。同じタイプではありません。

私はこのプログラムをコードしていますが、これを行う方法は想像できません。または、これがパフォーマンスやコード作成に適しているかどうか。私はちょうどCクラスを排除したいですが、私はどのように分かりません。

 
class MyClass 
{ 
    public: 
     MyClass() {} //contructor padrão, não deve ser utilizado isoladamente 

     virtual int a() = 0; 
     virtual int b() = 0; 

     int c() 
     { 
      return b(); 
     } 

}; 

class A : public MyClass 
{ 
    public: 
     int a() { return 1; } 
     int b() { return 1; } 
     int d() { return 1; } 
}; 

class B : public MyClass 
{ 
    public: 
     int a() { return 1; } 
     int b() { return 1; } 
     int e() { return 1; } 
}; 

class C 
{ 
public: 
    A ca; 
    B cb; 

    enum TIPO { A, B }; 
    TIPO Tipo; 

    C(TIPO tipo) { Tipo = tipo; } 

    int a() 
    { 
     switch(Tipo) 
     { 
     case A: 
      return ca.a(); 
      break; 
     case B: 
      return cb.b(); 
      break; 
     default: 
      break; 
     } 
    } 

}; 


void main() 
{ 
    C c(C::B); 
    c.a(); 
    return; 
} 
+0

あなたは何を求めているのですか?しかし、マルチスレッドをチェックしたいかもしれません –

答えて

0

あなたが「A」と「B」を書いたとして、あなたは実際にはCクラスは必要ありません。あなたのメンバ関数を宣言することにより「仮想」あなたは、実行時のポリモーフィズムを使用していて、これが「正しい」の機能になりますが呼び出されている:あなたはCから継承する必要があるいくつかの他の理由が

void foo (MyClass & mc) { 
    mc.a(); 
} 

int main() { 
    A a; 
    B b; 

    foo (a); // 'mc.a()' will call 'A::a' 
    foo (b); // 'mc.a()' will call 'B::a' 
} 

ありますか?

2

あなたが正しく理解している場合は、メンバー(ca、cb)を削除しようとしており、適切な基本クラスメソッドを呼び出すだけです。その場合は

は、使用することによって行うことができます。

switch(Tipo) { 
case A: 
    return A::a(); 
case B: 
    return B::a(); 
} 

しかし、私はあなたの設計を見直すことをお勧めします。典型的には、このような状況は、a()を定義する単一の基本クラスまたはインタフェースが存在するように、クラス設計を再考/再加工することによってしばしば処理され、2つの基本クラスを持つ1つの具象クラスを作成する代わりに、単一の基本クラスから派生した具象クラス。ここには複数の継承は必要ありません。

+0

2コロン! A :: a()とB :: a() – jmucchiello

+0

ありがとう - 単純なタイプミス - 修正。 –

0

まず、AクラスとBクラスが継承または合成によってCに属するかどうかを決定します。今は両方をやっています。どちらもコードを膨らませて混乱させてしまいます。

継承を行う場合、別の問題があります。同じ名前のオーバーライドされたメソッドは、Deadly Diamond of Death.の多重継承の主な原因です。聞いていない場合は悪です。仕事を終わらせる方法が他にない場合は避けてください。

あなたが作曲(私の推薦)と一緒に行くと、「同時にではない」というあなたの指定が不要になるようです。あなたは同じデータにアクセスしていないので、競合状態の可能性はありません。同じメモリ空間にアクセスしようとしている(根深い理由で)場合は、マルチスレッドをブラッシュアップする必要があります。その実装は、開発する各プラットフォームによって異なります。

+0

私はまたそれが "脆弱な基底クラス"の問題と呼ばれると聞いてきました。しかし、この場合、両方の継承クラスが同じ親を共有し、メソッドa()とb()をオーバーライドするので、問題です。経験豊富なプログラマーは、これらの両方のエラーを回避します。 – rtperson

+0

私は経験豊富なプログラマーですが、問題はありません。それは何ですか。しようとすると、()またはb()を使用する場合、コンパイラはあいまいさがあることを伝えます。続行する前にあいまいさを解決する必要があります。問題ない。経験豊富なプログラマーは、この問題だけで複数の継承を避けたいとは思わないでしょう(私はそれも主張していませんが)ここであなたの言葉を慎重に選ぶ必要があります..... –

+0

OPはここでポイントを狙っています。クラスはもはやAとBを継承しません。私はあなたの要点を見ていますが、StepanovとLeeのオリジナルのSTL実装の外では、複数の継承が、委譲や抽象的なインターフェースのどちらかでより洗練された方法で解決できない問題を解決することはめったにありません。また、複数の継承を使用する場合は、別々の関数セットを混在させ、OPと同様に、すでに密接に関連しているクラス同士を混乱させないようにします。それが私に、元気な曖昧さではなく誤ったエラーを引き起こす原因になります。 – rtperson

0

私は、C :: a()がCの "タイプ"または "モード"に応じてA :: a()またはB :: b()を呼び出すようにしたいと思います。まずCは、AとB

class C 
{ 
    private: 
    A ca; 
    B cb; 

    enum TIPO { A, B }; 
    TIPO Tipo; 

    public: 
    SetTipo(TIPO tipo) { Tipo = tipo; } 

    // .. 
}; 

void main() 
{ 
    C c(C::B); // Start with mode B and call B::b() 
    c.a(); 
    c.SetTipo(C::A); // Now I'm in mode A .. call A::a() 
    c.a(); 
    return; 
} 

を継承できるようにする必要はありませんこれは、Cが本当にAの1つのインスタンスを所有し、Bの1つのインスタンス必要があることを前提としていて、私はそれが何をしたいかどうかわかりません。あなたの質問は、それがそうであるかどうかを述べなかった。

乾杯

0

この質問は非常に不明です。私は答えと一緒に、質問の別の解釈を持っています。

解釈:与えられた:

class C { 
public: 
    int a(); 
    int b(); 
}; 

あなたは、実行時に選択可能な方法()または方法B()、のいずれかを呼び出したいです。解決策:メンバ関数ポインタ。

メンバー関数ポインタは、クラス内のメソッドに適用され、その型シグネチャには呼び出されたクラスの名前が含まれている点を除き、通常のC関数ポインタと似ています。

typedef int (C::*SELECT_FUNC)(void); 

メンバー関数ポインタの宣言です。これは、通常のC関数ポインタの宣言に似ていて、クラス名が追加されています。今、私たちはそれを割り当てることができます。

SELECT_FUNC ptr = &C::a; 
SELECT_FUNC other_ptr = &C::b; 

そして呼び出すために:

C item; 
C *item_ptr; 

int rv = item.*ptr(); 
int rv2 = item_ptr->*other_ptr; 

この構文は、ファンキーです。 "*"を "間接参照"と考えてください。私たちはメンバ関数ポインタを逆参照してMETHODを取得します。この時点で、通常の方法でメソッドを呼び出すことができます。

これはクールなことです。メソッドが仮想であるかどうかは関係ありません。メンバー関数ポインタに仮想メソッドまたは非仮想メソッドのいずれかを割り当てることができます。関数ポインタを介してメソッドを呼び出し、そのメソッドが仮想である場合、真の仮想呼び出しを取得します(つまり、関数ポインタが基本クラスメソッドを指すように宣言されていても、派生クラスインスタンスを"this"では、通常の仮想呼び出しの場合と同様に、派生クラスのメソッドが呼び出されます。)

私はあなたの要件を慎重に考えています。あなたの質問はうまく聞かれません。あなたが本当に望んでいることを自分で理解していないと私は信じます。達成したいことを理解したら、クラス階層またはメンバー関数ポインタ(またはその両方)を使用して問題を解決することをお勧めします。

関連する問題