我会回避你为什么需要这样一个方案,并专注于如何.
您可以使用 a 代替成员函数指针,std::function<double ()>
它是任何具有签名的可调用实体的通用包装器double foo()
。要创建一个std::function<double ()>
成员函数和一个对象实例,您可以使用std::bind
如下:
std::function<double ()> callback =
std::bind(&Class::memberFunction, objectInstancePointer);
如果您不使用 C++11,std::function和std::bind在 Boost 中也可以作为boost::function和boost::bind使用。这些的 Boost 文档大多(如果不是完全)适用于它们的 C++11 对应物。
代替 a std::vector
,您可以使用 astd::map
按名称索引 getter。这可能比维护参数 ID 号的中央列表更实用。
如果您的参数的类型可能与 不同double
,那么您可能需要考虑使用boost::any或boost::variant作为返回类型。
std::function
这是一个使用、std::bind
和的完整工作示例std::map
:
#include <cassert>
#include <map>
#include <iostream>
#include <functional>
class WithParametersBase
{
public:
WithParametersBase()
{
addGetter("X", std::bind(&WithParametersBase::getX, this));
addGetter("Y", std::bind(&WithParametersBase::getY, this));
}
virtual double getX() const {return 0.0;}
virtual double getY() const {return 1.0;}
// Access parameter by name
double getParameter(const std::string& name) const
{
auto getterIter = getters_.find(name);
assert(getterIter != getters_.end());
return getterIter->second();
}
protected:
typedef std::function<double ()> ParameterGetter;
typedef std::map<std::string, ParameterGetter> GetterMap;
void addGetter(const std::string& name, const ParameterGetter& getter)
{
getters_[name] = getter;
}
GetterMap getters_;
};
class WithParametersDerived : public WithParametersBase
{
public:
WithParametersDerived()
{
addGetter("Z", std::bind(&WithParametersDerived::getZ, this));
// Override base class getX
addGetter("X", std::bind(&WithParametersDerived::getX, this));
}
double getX() const {return 3.0;}
double getZ() const {return 2.0;} // A new getter
};
int main(int argc, char *argv[])
{
WithParametersBase base;
WithParametersDerived derived;
WithParametersBase& polymorphic = derived;
std::cout << base.getParameter("X")
<< base.getParameter("Y")
<< polymorphic.getParameter("X")
<< polymorphic.getParameter("Y")
<< polymorphic.getParameter("Z") << std::endl;
return 0;
}
这种方法的缺点是WithParametersBase
(或后代)的每个实例都将包含一个GetterMap
. 如果您有大量此类对象,则所有这些对象的内存开销GetterMaps
可能都是不可取的。
这是一个更有效的解决方案,它取消了std::function
and std::bind
。常规函数指针和静态成员函数用于 getter 回调。请求参数的对象实例作为参数传递给这些静态成员函数。在派生类型中,实例引用首先向下转换为派生类型,然后再调用执行实际获取的成员函数。
现在GetterMap
每个类而不是每个对象只有一个。注意在方法中使用“construct on first use”getters()
以避免静态初始化顺序惨败。
这种解决方案的缺点是每个派生自WithParametersBase
. 使用模板可能会减少样板代码的数量(使用宏肯定是可能的)。
#include <cassert>
#include <map>
#include <iostream>
class WithParametersBase
{
public:
virtual double getX() const {return 0.0;}
virtual double getY() const {return 1.0;}
// Access parameter by name
double getParameter(const std::string& name) const
{
auto getterIter = getters().find(name);
assert(getterIter != getters().end());
return getterIter->second(*this);
}
protected:
typedef double (*ParameterGetter)(const WithParametersBase& instance);
typedef std::map<std::string, ParameterGetter> GetterMap;
static double xGetter(const WithParametersBase& instance)
{
return instance.getX();
}
static double yGetter(const WithParametersBase& instance)
{
return instance.getY();
}
static GetterMap makeGetterMap()
{
GetterMap map;
map["X"] = &WithParametersBase::xGetter;
map["Y"] = &WithParametersBase::yGetter;
return map;
}
virtual const GetterMap& getters() const
{
// Not thread-safe. Use std::call_once to make thread-safe.
static GetterMap map = makeGetterMap();
return map;
};
};
class WithParametersDerived : public WithParametersBase
{
public:
double getX() const {return 3.0;}
double getZ() const {return 2.0;} // A new getter
protected:
static double zGetter(const WithParametersBase& instance)
{
// It's reasonably safe to assume that 'instance' is of type
// WithParametersDerived, since WithParametersDerived was the one
// that associated "Z" with this callback function.
const WithParametersDerived& derived =
dynamic_cast<const WithParametersDerived&>(instance);
return derived.getZ();
}
static GetterMap makeGetterMap()
{
// We "inherit" the getter map from the base class before extending it.
GetterMap map = WithParametersBase::makeGetterMap();
map["Z"] = &WithParametersDerived::zGetter;
return map;
}
virtual const GetterMap& getters() const
{
// Not thread-safe. Use std::call_once to make thread-safe.
static GetterMap map = makeGetterMap();
return map;
};
};
int main(int argc, char *argv[])
{
WithParametersBase base;
WithParametersDerived derived;
WithParametersBase& polymorphic = derived;
std::cout << base.getParameter("X")
<< base.getParameter("Y")
<< polymorphic.getParameter("X")
<< polymorphic.getParameter("Y")
<< polymorphic.getParameter("Z") << std::endl;
return 0;
}