gpt4 book ai didi

c++ - 如何为类的继承层次结构的getters创建一个统一的接口(interface)?

转载 作者:太空狗 更新时间:2023-10-29 20:29:01 25 4
gpt4 key购买 nike

我认为没有代码的任何解释都会更加晦涩。所以这里是我试图让一切尽可能简单的代码。

#include <vector>
#include <iostream>

class WithParametersBase
{
public:
WithParametersBase();

double getX() const {return 0.0;}
double getY() const {return 1.0;}

//let's say I want to access these members using an unified interface:

double getParameter(int index) const;

// For example index == 0 means getX and index == 1 means getY.
// I could implement it for example like this:

protected:

void addGetter(double (WithParametersBase::* getter)()const)
{
getters_.push_back(getter);
}

std::vector<double (WithParametersBase::*)()const> getters_;
};

WithParametersBase::WithParametersBase()
{
addGetter(&WithParametersBase::getX);
addGetter(&WithParametersBase::getY);
}

double WithParametersBase::getParameter(int index) const
{
return (this->*(getters_[index]))();
}

确实有效。带有测试程序:

int main(int argc, char *argv[])
{
WithParametersBase base;

std::cout << base.getParameter(0)
<< base.getParameter(1) << std::endl;

return 0;
}

打印输出是正确的:

01

但如果我想扩展这个类:

class WithParametersDerived : public WithParametersBase
{
public:
WithParametersDerived();
double getZ() const {return 2.0;} // A new getter
};

WithParametersDerived::WithParametersDerived()
{
// I want to integrate the new getter into the previous interface
addGetter(&WithParametersDerived::getZ);
}

所以如果我调用:

WithParametersDerived derived;
std::cout << derived.getParameter(2) << std::endl;

我想得到一个

2

我无法编译程序。我得到一个错误:

error: no matching function for call to
'WithParametersDerived::addGetter
(double (WithParametersDerived::*)()const)'

这是合理的,但我不知道如何实现它。

我希望派生类的创建者能够只添加新的 getter。我知道,在运行时做这一切感觉有点不对,但我没有看到模板解决方案或预处理器解决方案。如果您有一些建议,请告诉我。任何事物!

最佳答案

我将回避为什么您需要这样一个方案,并专注于如何

您可以使用 std::function<double ()> 而不是成员函数指针,它是围绕具有签名 double foo() 的任何可调用实体的通用包装器.创建 std::function<double ()>在成员函数和对象实例之外,您使用 std::bind如下:

std::function<double ()> callback =
std::bind(&Class::memberFunction, objectInstancePointer);

如果您不使用 C++11,std::functionstd::bind在 Boost 中也可用 boost::functionboost::bind .这些的 Boost 文档大部分(如果不是全部)适用于它们的 C++11 对应项。

而不是 std::vector , 你可以使用 std::map按名称索引 setter/getter 。这可能比维护参数 ID 编号的中央列表更实用。

如果您的参数可以是不同于 double 的类型, 那么您可能要考虑使用 boost::anyboost::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::functionstd::bind .常规函数指针和静态成员函数用于 getter 回调。请求参数的对象实例作为参数传递给这些静态成员函数。在派生类型中,实例引用首先向下转换为派生类型,然后调用执行实际获取的成员函数。

现在只有一个GetterMap 每个类而不是每个对象。请注意在 getters() 中使用“首次使用时构造”成语。避免的方法static initialization order fiasco .

此解决方案的缺点是要为派生自 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;
}

关于c++ - 如何为类的继承层次结构的getters创建一个统一的接口(interface)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11322433/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com