我有一个函数对象定义:
struct BaseFunctor
{
std::string desc = "Not this one!";
virtual double operator()(double a, double (*func) (double)) = 0;
};
以及一组派生函数对象定义:
struct DerivedFunctor1 : public BaseFunctor
{
std::string desc = "Yes this!";
virtual double operator()(double a, double (*func) (double))
{
return a * func(a);
}
};
struct DerivedFunctor2 : public BaseFunctor
{
std::string desc = "This is also correct!";
virtual double operator()(double a, double (*func) (double))
{
return 5 * a * func(a);
}
};
它们按以下方式实例化和使用:
double f1(double x){
return x*x+x;
}
template <typename T, typename F>
void do_something(T &func, F &derived)
{
double a = 1.0;
double res = derived(a, func);
std::cout << derived.desc << std::endl;
std::cout << "Result is: " << res << std::endl;
}
int main()
{
std::vector<BaseFunctor*> functors;
DerivedFunctor1 *derived1 = new DerivedFunctor1;
DerivedFunctor2 *derived2 = new DerivedFunctor2;
functors.push_back(derived1);
functors.push_back(derived2);
for (auto &f : functors)
{
do_something(f1, *f);
}
}
现在,这两个函数对象派生自 BaseFunctor 的原因是我可以将它们收集在标准容器中并迭代它们。是否有其他更有效的方法来迭代函数对象?
其次,运行代码输出
Not this one!
Result is: 2
Not this one!
Result is: 10
当我尝试访问成员变量desc
时,我得到了父类的成员变量。我可以编写 getter 并以这种方式访问派生函数对象的成员变量,但如果函数对象有很多成员变量,这似乎需要大量工作。还有其他方法可以实现这一目标吗?
最佳答案
除了现有的 BaseFunctor::desc
之外,您的派生类还定义了另一个名为 desc
的成员。
您更需要的是使用正确的字符串初始化BaseFunctor::desc
。示例:
#include <iostream>
#include <memory>
#include <vector>
struct BaseFunctor {
std::string const desc;
virtual double operator()(double a, double (*func) (double)) = 0;
virtual ~BaseFunctor() noexcept = default;
protected:
BaseFunctor(std::string desc) noexcept
: desc(move(desc))
{}
};
struct DerivedFunctor1 : public BaseFunctor {
DerivedFunctor1() : BaseFunctor("Yes this!") {}
double operator()(double a, double (*func) (double)) override { return a * func(a); }
};
struct DerivedFunctor2 : public BaseFunctor {
DerivedFunctor2() : BaseFunctor("This is also correct!") {}
double operator()(double a, double (*func) (double)) override { return 5 * a * func(a); }
};
template <typename T>
void do_something(T &func, BaseFunctor &derived) {
double a = 1.0;
double res = derived(a, func);
std::cout << derived.desc << '\n';
std::cout << "Result is: " << res << '\n';
}
double f1(double a) noexcept { return a * a + a; }
int main() {
using P = std::unique_ptr<BaseFunctor>;
std::vector<P> functors;
functors.push_back(P(new DerivedFunctor1));
functors.push_back(P(new DerivedFunctor2));
for (auto &f : functors)
do_something(f1, *f);
}
其他一些更改:
- 如果派生类的对象通过
BaseFunctor*
删除,并且您的代码建议这样做,BaseFunctor
必须具有一个virtual
析构函数。 - 派生类重写函数应使用
override
而不是virtual
,以便编译器在您尝试重写不存在或具有不同参数的函数时捕获错误,并且/或返回类型。在本例中,使用virtual
引入了一个同名的新函数重载。 std::unique_ptr
用于避免手动清理和内存泄漏。BaseFunctor::desc
设为const
,因此必须在BaseFunctor
的初始化器列表中对其进行初始化。这也使得 BaseFunctor 不可复制且不可移动,从而避免了通过切片意外复制派生类对象。
关于c++ - 如何迭代派生函数对象列表并访问派生对象成员变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61565796/