如何遍历派生函数对象列表并访问派生对象成员变量

How to iterate through list of derived function objects and accessing derived objects member variables

我有一个函数对象定义:

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时,我得到了父class的成员变量。我可以编写 getter 并以这种方式访问​​派生函数对象的成员变量,但如果函数对象有很多成员变量,这似乎需要大量工作。还有其他方法可以实现这一目标吗?

除了现有的 BaseFunctor::desc.

,您派生的 class 还定义了另一个名为 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 必须有一个 virtual 析构函数,如果派生 classes 的对象通过 BaseFunctor* 被删除,并且您的代码表明。
  • 派生的 classes 重写函数应该使用 override 而不是 virtual 以便编译器在您尝试重写不存在或具有不同参数的函数时捕获错误and/or return 类型。 virtual 它引入了一个新的同名函数重载,在这种情况下。
  • std::unique_ptr用于避免手动清理和内存泄漏。
  • BaseFunctor::desc做了const,所以必须在BaseFunctor中的初始化列表中初始化。这也使得 BaseFunctor 不可复制且不可移动,这避免了意外复制带有切片的派生 class 对象。

使用相同参数调用常量 函数的示例,如评论中所述。参见(重载)函数 call_all:

#include <iostream>

void call_all() {
    // Does nothing, just stops the recursion.
}

template<typename Current, typename... Args>
void call_all(Current current_function, Args... args) {
    current_function();
    call_all(args...);
}

void func1() {
    std::cout << "func1" << std::endl;
}

void func2() {
    std::cout << "func2" << std::endl;
}

int main() {
    // Pass anything that implements operator() here.
    call_all(func1, func2);
}