如何遍历派生函数对象列表并访问派生对象成员变量
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);
}
我有一个函数对象定义:
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
.
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);
}