是否可以将指向函数成员的指针保存在基类使用的另一个类中

时间:2014-07-03 06:16:25

标签: c++ reference member-function-pointers

基本上我有一个课程,让我们说Parameter有一个get和set变量。

我还有一个基类让我们说Vehicle有一个方法registerParameter(...),它将一个指向函数成员的指针作为getter,一个指向函数成员的指针作为setter。然后,该方法应该将这两个指针写入参数类的对象,并将此对象抛出到向量中。

最后但并非最不重要的是,我们有一个派生类,让我们说Car,我们用registerParameter(...)作为参数名称调用"color",并使用此函数调用getter和setter衍生类。

代码示例:

参数文件

#ifndef BASE_H
#define BASE_H
#include "base.h"

class Parameter
{
    std::string (Base::*get)();
void (Base::*set)(std::string);
};

#endif

基础文件

#ifndef PARAMETER_H
#define PARAMETER_H
#include <vector>
#include "parameter.h"

class Base
{
  public:
std::vector<Parameter> list;
void registerNew(std::string (Base::*get)(), void (Base::*set)(std::string))
    {
        Parameters parameter;
        parameter.get = get;
        parameter.set = set;
        list.push_back(parameter);
}
};

#endif

派生文件

class Derived
{
  public:
    Derived derived() 
    {
        registerNew(&getColor, &setColor);
    }

    std::string getColor()
    {
        return this->color;
    }

    std::string setColor(std::string newColor)
    {
        this->color = newColor;
    }
  private:
    std::string color;
};

我几天来一直在考虑这个问题,直到星期五晚上我才真正需要这个解决方案。

2 个答案:

答案 0 :(得分:1)

你不能做正在尝试的事情:

std::string (Base::*)()std::string (Derived::*)()类型非常不同。 std::string (Derived::*)()无法自动转换为std::string (Base::*)()

采取以下方案。

struct Base
{
    int foo() { return 10; }
};

struct Derived : Base
{
    int bar() { return 20; }
};

int main()
{
    Base base;

    int (Base::*bf)() = &Base::foo;
    (base.*bf)(); // Should be able to call Base:foo(). No problem.

    bf = &Derived::bar; // This is a compiler error. However, if this were allowed....
    (base.*bf)(); // Call Derived::bar()?? That will be a problem. base is not an
                  // instance of Derived.
}

<强>更新

您可以执行以下操作:

#include <string>
#include <vector>

class Base;

// Create a base class Functor that provides the interface to be used by
// Base.
struct Functor
{
   virtual ~Functor() {}
   virtual std::string get(Base& base) = 0;
   virtual void set(Base& base, std::string) = 0;
};

// Create a class template that implements the Functor interface.
template <typename Derived> struct FunctorTemplate : public Functor
{
   // typedefs for get and set functions to be used by this class.
   typedef std::string (Derived::*GetFunction)();
   typedef void (Derived::*SetFunction)(std::string);

   // The constructor that uses the get and set functions of the derived
   // class to do itw work.
   FunctorTemplate(GetFunction get, SetFunction set) : get_(get), set_(set) {}

   virtual ~FunctorTemplate() {}

   // Implement the get() function.
   virtual std::string get(Base& base)
   {
      return (reinterpret_cast<Derived&>(base).*get_)();
   }

   // Implement the set() function.
   virtual void set(Base& base, std::string s)
   {
      (reinterpret_cast<Derived&>(base).*set_)(s);
   }

   GetFunction get_;
   SetFunction set_;
};

class Base
{
   public:
      std::vector<Functor*> functorList;

      void registerFunctor(Functor* functor)
      {
         functorList.push_back(functor);
      }
};

class Derived : public Base
{
  public:
    Derived() 
    {
       // Register a FunctorTemplate.
       registerFunctor(new FunctorTemplate<Derived>(&Derived::getColor, 
                                                    &Derived::setColor));
    }

    std::string getColor()
    {
        return this->color;
    }

    void setColor(std::string newColor)
    {
        this->color = newColor;
    }
  private:
    std::string color;
};

答案 1 :(得分:0)

您的基类应该知道派生类。这听起来很复杂,但问题已经解决了:

template<typename DERIVED> class Base
{
public:
   class Parameter {
     std::string (DERIVED::*get)();
     void (DERIVED::*set)();
   };
private:
   std::list<Parameter> list;
   // ...
};

class Derived : public Base<Derived> // !!!
{
   registerNew(&Derived::getColor, &Derived::setColor);
};

此解决方案称为奇怪的重复模板模式(CRTP)。