【问题标题】:How to assign method member pointer of a subclass?如何分配子类的方法成员指针?
【发布时间】:2012-11-25 17:29:45
【问题描述】:

我的问题有点复杂。 我有一个具有 Ports 对象的类(e:Component)。 当组件创建一个 Port 对象时,它会将其方法之一传递给 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);

嗯...现在,我的问题是我创建了 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) 方法。

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

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

任何帮助将不胜感激:)

【问题讨论】:

    标签: c++ templates subclass member-function-pointers mem-fun


    【解决方案1】:

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

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

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

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        【解决方案3】:

        您可以使用模板适配器,因为可以转换指向成员的指针,这样:

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

        【讨论】:

          【解决方案4】:

          最简单的方法可能是让 Component 有一个名为 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 casting

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-03-24
            • 2021-12-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多