3

私の問題は少し複雑です。Ports オブジェクトを持つ 1 つのクラス (e: コンポーネント) があります。Component が Port オブジェクトを作成するとき、そのメソッドの 1 つを Port コンストラクターに渡します。

メソッドのシグネチャ :

typedef std::vector<std::string> (Component::*ComponentMethod)(std::vector<std::string>);

私がすればそれはうまくいきます:

// in class Component

std::vector<std::string> Component::test_method( std::vector<std::string> ) {
    std::cout << "Hello !\n";
    // Do stuff
}

// Port ctor : Port( ComponentMethod callback );
Port* p = new Port(&Component::test_method);

さて...今、私の問題は、コンポーネント クラスのサブクラスを作成し、サブクラス メソッドをポートに渡す方法がわからないことです。

// in class SubtypeComponent

std::vector<std::string> SubtypeComponent::test_method2( std::vector<std::string> ) {
    std::cout << "Hello !\n";
    // Do stuff
}

// Port ctor : Port( ComponentMethod callback );
Port* p = new Port(&SubtypeComponent::test_method2);
// ERROR :'(

それは正常なようです:コンパイラは正確にコンポーネント(のみ)メソッドを期待していると思います。

--> Ports でメソッドを「動的に」割り当てるための解決策を探しています (しかし、これが可能だとは思いません)。

--> 多分別の解決策はテンプレートの使用でしょうか? (「コンポーネントメソッドポインター」ではなく「テンプレートメソッドポインター」を定義しています)が、よくわかりません。

どんな助けでも大歓迎です:)

4

4 に答える 4

2

ポインターからメンバーへの変換は、最初は少し直感的ではありません。基本メンバーを参照するメンバーへのポインターは、派生型へのメンバーへのポインターに暗黙的に変換できますが (反分散)、その逆は当てはまりません。

本当に考えてみれば、それは理にかなっています: base のメンバーへのポインターがある場合、派生型に適用できます。これは、base サブオブジェクトがあることが保証されているためです。逆に、派生型を参照するメンバーへのポインターは、基本型に存在しないメンバーを指している可能性があるため、変換は意味がありません。

これは、対処しなければならない設計の問題です。基本型を参照するメンバーへのポインターを保持する場合、ポインターは基本型に存在するメンバーを参照する必要があります (この場合、式&derived::memberは型T base::*であり、変換する必要はありません) また、以前に構造型のメンバーへのポインターに格納されていてはなりません (格納後、コンパイラーは、ポインターがベースのメンバーを参照しているのか、派生型のメンバーを参照しているのかを知ることができません)。

于 2012-11-25T17:36:03.480 に答える
1

メンバーへのポインタは次のようにキャストできるため、テンプレート アダプタを使用できます。

struct Base {
  bool foo(int);
};

struct Child : Base {
  bool foo(int);
};

// real functional type
using Function = std::function<bool(Base*,int)>;
// adapter template for children classes member functions
template <class T>
using MemberFunction = (T::*)(int);

// real user function
void user(Function function);
// adapter template for children classes member functions
template <class T>
void user(MemberFunction<T> function) {
  // pointers-to-members can be casted
  user(static_cast<MemberFunction<Base>>(function));
}
于 2015-09-03T22:30:33.187 に答える
1

派生型のメンバーへのポインターをベースのメンバーへのポインターに変換することは明らかにできません。これにより、型システムを混乱させることなく、ベース オブジェクトで派生型のメンバーを呼び出すことができます。どちらかといえば、変換は逆に機能するはずです。つまり、基底型のメンバーへのポインターを派生型のメンバーへのポインターに変換できる可能性があります (ただし、これも不可能だと思います)。 、 確信はないけど)。

この問題を完全に回避する方法は、型消去された関数型を使用して渡すことです。たとえば、 を使用してstd::function<std::vector<std::string>(std::vector<std::string>)、オブジェクトを参照するように設定できます。異なるオブジェクトを引数として渡す必要がある場合は、ポインタまたは参照をベースに渡し、dynamic_cast<D&>(r)それを期待される型に渡すことができます (間違ったオブジェクトで呼び出された場合は例外を処理します)。

于 2012-11-25T17:39:34.943 に答える
0

これを行う最も簡単な方法は、Component にたとえば と呼ばれる仮想メソッドを持たせることですtest_method。次に、Component へのポインターを Port のコンストラクターに渡すことができ、Port はこの仮想メソッドを呼び出すことができます。

Component* c = new Component();
// Port ctor : Port( Component* component );
Port* p = new Port(c); // Port would then call c->test_method();

また

SubtypeComponent* sc = new SubtypeComponent();
// Port ctor : Port( Component* component );
Port* p = new Port(sc); // Port would then call sc->test_method();

ただし、何らかの理由でこれで十分な柔軟性が得られない場合は、問題を解決する別の方法があります。メソッド ポインターの代わりに型を渡す必要があります。この型は、メソッド (およびオブジェクトなしでメソッドを呼び出すことができないため、オブジェクト) を保持します。このタイプの例を次に示します (C++11 が利用可能な場合は、std::function を使用することもできます)。

class Handler {
    public:
    virtual std::vector<std::string> handle (std::vector<std::string> arguments) = 0;
};

template <class C> class Method: public Handler {
    C* object;
    std::vector<std::string> (C::*method) (std::vector<std::string>);
    public:
    Method (C *object, std::vector<std::string>(C::*method)(std::vector<std::string>)) {
        this->object = object;
        this->method = method;
    }
    virtual std::vector<std::string> handle (std::vector<std::string> arguments) {
        // call the method
        return (object->*method) (arguments);
    }
};

ここで、Port クラスのコンストラクターを変更して、ハンドラーへのポインターを引数として受け取ります。次に、次のように記述できます。

Component* c = new Component();
// Port ctor : Port( Handler* handler );
Port* p = new Port(new Method<Component>(c, &Component::test_method));

SubtypeComponent* sc = new SubtypeComponent();
// Port ctor : Port( Handler* handler );
Port* p = new Port(new Method<SubtypeComponent>(sc, &SubtypeComponent::test_method2));

これらの質問も参照してください。
クラスおよびサブクラスの C++ メンバー関数ポインター
メソッド ポインターのキャスト

于 2013-03-04T20:00:20.037 に答える