C++ 将任何类型的object函数传递给C+中的另一个object+;
我正在创建一个节点系统(类似于UE4或Blender's Cycles),在其中我可以创建不同类型的节点,并在以后使用它们。目前,我有两类节点,其输出函数如下:C++ 将任何类型的object函数传递给C+中的另一个object+;,c++,C++,我正在创建一个节点系统(类似于UE4或Blender's Cycles),在其中我可以创建不同类型的节点,并在以后使用它们。目前,我有两类节点,其输出函数如下: class InputInt { public: int output() { int x; std::cin>>x; return x; } }; class RandomInt { public: int rand10() {
class InputInt
{
public:
int output()
{
int x;
std::cin>>x;
return x;
}
};
class RandomInt
{
public:
int rand10()
{
int x;
x = rand()%10;
return x;
}
int rand100()
{
int x;
x = rand()%100;
return x;
}
};
我不向这些节点传递任何内容。现在我想创建一个节点,该节点从上述一个类的对象获取并输出函数。下面是我如何实现它以仅使用InputInt
节点:
class MultiplyBy2
{
typedef int (InputInt::*func)();
func input_func;
InputInt *obj;
public:
MultiplyBy2(InputInt *object, func i): obj(object), input_func(i) {}
int output()
{
return (obj->*input_func)()*2;
}
};
有了这一点,我可以在main()
中创建并使用multiplyy2
的对象,它工作得非常好
int main()
{
InputInt input;
MultiplyBy2 multi(&input, input.output);
std::cout<<multi.output()<<std::endl;
}
你可以用
模板
类倍数2
{
typedef int(underyingclass::*func)();
func输入函数;
底层类*obj;
公众:
multiplyy2(underlyngClass*对象,func i):obj(对象),input_func(i){
int输出()
{
返回(obj->*输入函数)(*2;
}
};
int main()
{
//试验
输入ii;
multiply2mii{&ii,&InputInt::output};
随机点ri;
multiply2mri{&ri,&RandomInt::rand10};
}
这有点复杂。但是,我认为您应该创建一个返回值的接口或类,并且对象应该从中继承。然后操作符类可以接受从基/接口继承的任何类。例如,创建一个存储int并具有输出方法/RandomInt和InputInt的BaseInt类,InputInt应继承自BaseInt另一种方法,使用带有虚拟方法的公共基类:
#include <iostream>
struct IntOp {
virtual int get() = 0;
};
struct ConstInt: IntOp {
int n;
explicit ConstInt(int n): n(n) { }
virtual int get() override { return n; }
};
struct MultiplyIntInt: IntOp {
IntOp *pArg1, *pArg2;
MultiplyIntInt(IntOp *pArg1, IntOp *pArg2): pArg1(pArg1), pArg2(pArg2) { }
virtual int get() override { return pArg1->get() * pArg2->get(); }
};
int main()
{
ConstInt i3(3), i4(4);
MultiplyIntInt i3muli4(&i3, &i4);
std::cout << i3.get() << " * " << i4.get() << " = " << i3muli4.get() << '\n';
return 0;
}
正如我在与OP的回答后对话中提到的,
std::function
,我对这个想法做了一些修改,得到了以下结论:
#include <iostream>
#include <functional>
struct MultiplyIntInt {
std::function<int()> op1, op2;
MultiplyIntInt(std::function<int()> op1, std::function<int()> op2): op1(op1), op2(op2) { }
int get() { return op1() * op2(); }
};
int main()
{
auto const3 = []() -> int { return 3; };
auto const4 = []() -> int { return 4; };
auto rand100 = []() -> int { return rand() % 100; };
MultiplyIntInt i3muli4(const3, const4);
MultiplyIntInt i3muli4mulRnd(
[&]() -> int { return i3muli4.get(); }, rand100);
for (int i = 1; i <= 10; ++i) {
std::cout << i << ".: 3 * 4 * rand() = "
<< i3muli4mulRnd.get() << '\n';
}
return 0;
}
使用std::function
,类方法、独立函数甚至lambda都可以组合使用。因此,节点不再需要基类。实际上,甚至不再需要节点(显式)(如果独立函数或lambda不算作“节点”)
我必须承认,图形数据流编程是我在大学的最后一项工作的主题(尽管这是很久以前的事了)。我记得我很出色
- 需求驱动执行vs
- 数据驱动执行
const3
和const4
)可能会将新结果推送到其输出,这可能会导致也可能不会导致以下操作重新计算
对于图形表示,操作员类还应提供某种基础设施(例如,检索名称/类型和可用的输入和输出,以及可能的状态更改通知信号)
当然,可以将这两种方法(数据驱动和需求驱动执行)结合起来。(中间的一个节点可能会改变它的状态,并要求新的输入以推动新的输出。)看看我在这里建模了一些类似抽象语法树(具有执行特性)的东西。我相信,通过稍微不同的类设计解决了这个问题。这就是我在回答中实现的。:-)(除了我使用了一个方法
get()
而不是重载操作符()()
)如果我错了,请纠正我,但是使用这种方法,我认为我无法为一个节点创建多个输出,例如,RandomInt
有两个不同的输出,我想指定要使用的输出。如果您的方法能做到这一点,我将非常感谢您的解释。@koman900如在compint
中所述,您可以将这些运算符参数化。你也可以引入变量
或赋值
(但这将打破它在这种状态下的纯函数方法)。@koman900但我同意,在这种设计中:一类-一类运算符。(我称之为函子,即使没有<代码>运算符)(()< /代码>。我不认为这是限制……KOMAN900AH——数据流语言。(我以前没有看到这张图片。)对于这种情况,我将介绍可以输出元组类型的函子。(通过这种方式,我们在我们的专业软件中实现了。)…和一个类型系统。但这需要比上面代码中的行多一点。:-)@koman900 I添加了第三个示例和一些关于数据驱动与需求驱动执行的注释。
#include <iostream>
struct IntOp {
virtual int get() = 0;
};
struct ConstInt: IntOp {
int n;
explicit ConstInt(int n): n(n) { }
virtual int get() override { return n; }
};
struct MultiplyIntInt: IntOp {
IntOp *pArg1, *pArg2;
MultiplyIntInt(IntOp *pArg1, IntOp *pArg2): pArg1(pArg1), pArg2(pArg2) { }
virtual int get() override { return pArg1->get() * pArg2->get(); }
};
int main()
{
ConstInt i3(3), i4(4);
MultiplyIntInt i3muli4(&i3, &i4);
std::cout << i3.get() << " * " << i4.get() << " = " << i3muli4.get() << '\n';
return 0;
}
#include <iostream>
#include <functional>
struct MultiplyIntInt {
std::function<int()> op1, op2;
MultiplyIntInt(std::function<int()> op1, std::function<int()> op2): op1(op1), op2(op2) { }
int get() { return op1() * op2(); }
};
int main()
{
auto const3 = []() -> int { return 3; };
auto const4 = []() -> int { return 4; };
auto rand100 = []() -> int { return rand() % 100; };
MultiplyIntInt i3muli4(const3, const4);
MultiplyIntInt i3muli4mulRnd(
[&]() -> int { return i3muli4.get(); }, rand100);
for (int i = 1; i <= 10; ++i) {
std::cout << i << ".: 3 * 4 * rand() = "
<< i3muli4mulRnd.get() << '\n';
}
return 0;
}
#include <iostream>
#include <vector>
#include <functional>
struct ConstInt {
int n;
std::vector<std::function<void(int)>> out;
ConstInt(int n): n(n) { eval(); }
void link(std::function<void(int)> in)
{
out.push_back(in); eval();
}
void eval()
{
for (std::function<void(int)> &f : out) f(n);
}
};
struct MultiplyIntInt {
int n1, n2; bool received1, received2;
std::vector<std::function<void(int)>> out;
void set1(int n) { n1 = n; received1 = true; eval(); }
void set2(int n) { n2 = n; received2 = true; eval(); }
void link(std::function<void(int)> in)
{
out.push_back(in); eval();
}
void eval()
{
if (received1 && received2) {
int prod = n1 * n2;
for (std::function<void(int)> &f : out) f(prod);
}
}
};
struct Print {
const char *text;
explicit Print(const char *text): text(text) { }
void set(int n)
{
std::cout << text << n << '\n';
}
};
int main()
{
// setup data flow
Print print("Result: ");
MultiplyIntInt mul;
ConstInt const3(3), const4(4);
// link nodes
const3.link([&mul](int n) { mul.set1(n); });
const4.link([&mul](int n) { mul.set2(n); });
mul.link([&print](int n) { print.set(n); });
// done
return 0;
}