C++ 将任何类型的object函数传递给C+中的另一个object+;

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() {

我正在创建一个节点系统(类似于UE4或Blender's Cycles),在其中我可以创建不同类型的节点,并在以后使用它们。目前,我有两类节点,其输出函数如下:

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;
}