3

我的问题有点复杂。我有一个具有 Ports 对象的类(e:Component)。当一个组件创建一个端口对象时,它会将其方法之一传递给端口构造函数。

方法签名:

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);

嗯...现在,我的问题是我创建了 Component 类的子类,但我不知道如何将 sublcasses 方法传递给 Port。

// 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 :'(

看起来很正常:我猜编译器需要精确的 Component (only) 方法。

--> 我正在寻找在端口中“动态”分配方法的解决方案(但我认为这是不可能的)

--> 也许另一个解决方案应该是使用模板?(定义“模板方法指针”而不是“组件方法指针”),但我不确定。

任何帮助,将不胜感激 :)

4

4 回答 4

2

指针到成员的转换起初有点反直觉。指向基成员的指向成员的指针可以隐式转换为指向派生类型的指向成员的指针(相反的变化),但反之则不然。

如果您真的考虑一下,它确实是有道理的:如果您有一个指向基成员的指针,那么它可以应用于派生类型,因为它保证有一个基子对象。相反,指向派生类型的成员的指针可能指向基类型中不存在的成员,因此转换没有意义。

这是您的设计中必须解决的问题,如果您想持有指向基类型的成员指针,则指针必须引用基中存在的成员(在这种情况下,表达式&derived::member是类型T base::*并且存在无需转换),并且它们之前不能存储在派生类型的指向成员的指针中(存储后,编译器无法知道指针是指基的成员还是派生的成员)

于 2012-11-25T17:36:03.480 回答
1

您显然不能将指向派生类型成员的指针转换为指向基类成员的指针:这将允许在基对象上调用派生类型的成员而不会破坏类型系统!如果有的话,转换应该以相反的方式工作,即,您可能能够将指向 a 成员的指针转换为指向派生类型成员的指针(但是,我认为这也是不可能的,但我不确定)。

完全绕过这个问题的方法是使用类型擦除的函数类型来传递。例如,您可以使用 astd::function<std::vector<std::string>(std::vector<std::string>)并将其设置为引用您的对象。如果您确实需要传入不同的对象作为参数,您可以将指针或对基的引用传递dynamic_cast<D&>(r)给预期的类型(如果在错误的对象上调用异常,则处理异常)。

于 2012-11-25T17:39:34.943 回答
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 回答
0

最简单的方法可能是让 Component 有一个名为 example 的虚拟方法test_method。然后你可以将一个指向组件的指针传递给 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 类构造函数以将指向 Handler 的指针作为参数。然后你可以写:

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++ member function pointers in class and subclass
Method pointer cast

于 2013-03-04T20:00:20.037 回答