0

C++ には興味深い問題がありましたが、それはアーキテクチャに関するものでした。

いくつかの特性 (ミックスイン クラス) を記述する多く (10、20、40 など) のクラスがあります。次に例を示します。

struct Base { virtual ~Base() {} };

struct A : virtual public Base { int size; };
struct B : virtual public Base { float x, y; };
struct C : virtual public Base { bool some_bool_state; };
struct D : virtual public Base { string str; }
// ....

プライマリ モジュールは、関数を宣言してエクスポートします (簡単にするために、クラスなしで関数宣言のみを行います)。

// .h file
void operate(Base *pBase);

// .cpp file
void operate(Base *pBase)
{
    // ....
}

他のモジュールには、次のようなコードを含めることができます。

#include "mixing.h"
#include "primary.h"

class obj1_t : public A, public C, public D {};
class obj2_t : public B, public D {};

// ...
void Pass()
{
    obj1_t obj1;
    obj2_t obj2;

    operate(&obj1);
    operate(&obj2);
}

問題は、クラス内の型情報 (定数など)operate()を使用せずに、指定されたオブジェクトの実際の型が何であるかをどのように知ることができるかということです。dynamic_castこのoperate()関数は、短期間にオブジェクトの大きな配列で使用され、遅すぎます。これは OOP の方法ではないためdynamic_cast、定数 ( ) を含めたくありません。enum obj_type { ... }

// module operate.cpp

void some_operate(Base *pBase)
{
    processA(pBase);
    processB(pBase);
}

void processA(A *pA)
{
}

void processB(B *pB)
{
}

pBaseこれらの関数にa を直接渡すことはできません。また、新しいヘッダー ファイルをインクルードするだけで新しいクラスを追加できるため、考えられるすべてのクラスの組み合わせを持つことは不可能です。

思いついた解決策の 1 つは、エディターで複合コンテナーを使用できることです。

struct CompositeObject
{
    vector<Base *pBase> parts;
};

ただし、エディターは時間の最適化を必要とせずdynamic_cast、パーツを使用して正確なタイプを決定できます。このoperate()ソリューションを使用できません。

dynamic_castでは、この問題を解決するために a と型の情報を使用しないようにすることは可能でしょうか? それとも、別のアーキテクチャを使用する必要がありますか?

4

4 に答える 4

2

ここでの本当の問題は、何を達成しようとしているのかということです。

次のようなものが欲しいですか:

void operate(A-B& ) { operateA(); operateB(); }

// OR

void operate(A-B& ) { operateAB(); }

つまり、各サブコンポーネントに (独立して) 操作を適用したいですか、それともコンポーネントの組み合わせに応じて操作を適用できるようにしたいですか (はるかに難しい)。

ここで最初のアプローチをとります。

1.仮想?

class Base { public: virtual void operate() = 0; };

class A: virtual public Base { public virtual void operate() = 0; };
void A::operate() { ++size; } // yes, it's possible to define a pure virtual

class obj1_t: public A, public B
{
public:
  virtual void operate() { A::operate(); B::operate(); }
};

確かに、もう少し仕事があります。特に私は繰り返しがあまり好きではありません。しかし、これは _vtable への 1 回の呼び出しなので、最速のソリューションの 1 つになるはずです!

2.複合パターン

こちらの方が自然かもしれません。

C++ では、パターンのテンプレート バージョンを完全に使用できることに注意してください。

template <class T1, class T2, class T3>
class BaseT: public Base, private T1, private T2, private T3
{
public:
  void operate() { T1::operate(); T2::operate(); T3::operate(); }
};

class obj1_t: public BaseT<A,B,C> {};

利点:

  • もう繰り返す必要はありません。一度だけ書いoperateてください(可変引数をむき出しにして...)
  • 仮想呼び出しは 1 つだけで、仮想継承がなくなるため、以前よりもさらに効率的になります。
  • ABおよびC任意の型にすることができます。それらはまったく継承すべきではありませBase
  • operateメソッドを編集します。インライン化されていないため、インライン化される可能性がAありBますCvirtual

不利益:

可変個引数テンプレートにまだアクセスできない場合は、フレームワークでさらに作業を行いますが、数十行以内で実行可能です。

于 2010-04-08T12:07:17.627 に答える
2

最初に頭に浮かぶのは、本当に達成したいことを尋ねることです...しかし、2番目の考えは、訪問者パターンを使用できるということです。実行時型情報は、階層内のどの時点で accept メソッドの最終オーバーライドであるかを決定するために暗黙的に使用されますが、その情報を明示的に使用することはありません (コードにはdynamic_cast, type_info, 定数は表示されません...)

それからまた、私の最初の考えが戻ってきます.あなたはアーキテクチャの適切性について尋ねているので、あなたが本当に達成したいことは何ですか? -- 問題の知識がなければ、このような一般的な回答しか見つかりません。

于 2010-04-08T11:01:22.763 に答える
1

あなたの問題は、複数のオブジェクトのタイプに基づいて何をすべきかを決定したいということです。仮想関数は、これを 1 つのオブジェクト (.またはの左側のオブジェクト->) に対してのみ行います。複数のオブジェクトに対してこれを行うことは、複数ディスパッチと呼ばれます (2 つのオブジェクトの場合は、ダブル ディスパッチとも呼ばれます)。C++ には、これを処理するための組み込み機能はありません。

特に訪問者パターンで行われているように、二重発送を見てください。

于 2010-04-08T11:09:24.803 に答える
1

operate()通常のオブジェクト指向の方法は、派生クラスに固有のコードを実行するために呼び出され、派生クラスでオーバーライドされる (純粋な) 仮想関数を基底クラスに持つことです。

于 2010-04-08T11:01:39.547 に答える