如何最好地将方法传递给同一类的方法

Posted

技术标签:

【中文标题】如何最好地将方法传递给同一类的方法【英文标题】:How to best pass methods into methods of the same class 【发布时间】:2012-06-29 10:36:55 【问题描述】:

我有一个 C++ 类,它是一个大而复杂的方法compute,我想用“计算内核”提供它,这是同一个类的方法。我想我会做一些类似的事情

class test 
int classVar_ = 42;

int compute_add(int a, int b)

   compute(int a, int b, this->add_())


int compute_mult(int a, int b)

   compute(int a, int b, this->mult_())



int compute_(int a, int b, "pass in add or multiply as f()")

   int c=0;
   // Some complex loops 
   c += f(a,b)
   // 
   return c;


int add_(int a, int b)a+b+classVar_;
int multiply_(int a, int b)a*b+classVar_;
...


但我不确定如何传入addmultiply。 这种方法的替代方法是传入某种ENUM 来指定add()multiply(),但我想避免在循环中使用switchif

这里的最佳做法是什么?

【问题讨论】:

您有一个member-function-pointers 标签。这不是一个好的开始吗? @chris 我猜他对语法感到困惑? 如果您要传递的方法与您的示例中一样,普通(静态)函数和普通函数指针就足够了。 @RedX,Google 并不是真正的问题,因为它是源代码的一个非常常见的主题。 【参考方案1】:

正如您所怀疑的,传递成员函数指针是可以接受的做法。

如果你需要知道语法,那就是:

int compute_(int a, int b, int (test::*f)(int,int))

   int c=0;
   // Some complex loops 
   c += (this->*f)(a,b)
   // 
   return c;

使用整数表示成员函数和切换会引入程序员开销,以便在可用操作列表更改时保持最新状态。所以你不希望这样,除非在特定情况下有一些重要的原因。

另一种方法是使compute 更加通用——而不是采用成员函数,而是编写一个采用任何可调用类型的函数模板:

template <typename BinaryFunction>
int compute_(int a, int b, BinaryFunction f) 
    // body as before but `f(a,b)` instead of `(this->*f)(a,b)`

如果有人想将它与他们自己发明的某个运算符一起使用,这个更通用的模板非常棒,这不是test 的成员函数。但是,在成员函数的情况下使用起来更加困难,因为需要有人捕获this。有几种方法可以做到这一点——C++11 lambda,boost::bind,或者写出一个仿函数。例如:

template <typename BinaryFunction>
int compute_(int a, int b, BinaryFunction f) 
    // body as before with `f(a,b)`


int compute_(int a, int b, int (test::*f)(int,int))

    return compute_(a, b, bind_this(f, this));

定义bind_this 有点麻烦:它就像std::bind1st,只是我们想使用3-arg 仿函数,而bind1st 只使用二元仿函数。 C++11 中的boost::bindstd::bind 更加灵活,并且会处理额外的参数。以下方法适用于这种情况,但通常不适用于绑定 2-arg 成员函数:

struct bind_this 
    int (test::*f)(int,int);
    test *t;
    int operator(int a, int b) const 
        return (t->*f)(a,b);
    
    bind_this(int (test::*f)(int,int), test *t) : f(f), t(t) 
;

在 C++11 中,您可以只使用 lambda:

int compute_(int a, int b, int (test::*f)(int,int))

    return compute_(a, b, [=](int c, int d) return (this->*f)(c,d) );

【讨论】:

你怎么称呼compute_(int a, int b, int (test::*f)(int,int))compute_(1,2,this-&gt;add_) 产生 cannot initialize a parameter of type 'int (test::*)(int, int)' with an rvalue of type '&lt;bound member function type&gt;'compute_(1,2,&amp;this-&gt;add_) 产生 cannot create a non-constant pointer to member function @Nico:试试compute_(1,2,add_) @Mat 嗯,这和this-&gt;add_ 是一样的,额外的限定符只告诉编译器在哪里寻找add_ GCC 更具体:ISO C++ forbids taking the address of a bound member function to form a pointer to member function.(这是&amp; 的情况)。我发现***.com/questions/2374847/… 是一个非常相似的问题。让我看看这个。 @Nico:我将其称为compute_(1,2,&amp;test::add_),但我准备相信Mat 的建议在test 类的范围内是正确的。显然,this-&gt;_add 在形成指向成员函数的指针时与_add不同相同,即使在调用该成员函数时它是相同的。【参考方案2】:

使用指向函数的指针。

int compute(int a, int b, int (test::*f) (int, int) )

   int c=0;
   // Some complex loops 
   c += (this->*f)(a,b)
   // 
   return c;

【讨论】:

【参考方案3】:

你有两种选择:

    使用pointer to member function 使用lambda functions

使用指向成员函数的指针的示例:

#include <iostream>

class D

public:
  D(int v ) : classVar_(v)
  int add_(int a, int b)return (a+b+classVar_);
  int multiply_(int a, int b)return (a*b+classVar_);
private:
  int classVar_;
;

class test 
public:

int compute_(int a, int b, D &d, int (D::*f)(int a, int b))

   int c=0;
   // Some complex loops 
   c += (d.*f)(a,b);
   // 
   return c;


;

int main()

  test test;
  D d(1);

  std::cout<<"add : " << test.compute_( 5, 4, d, &D::add_ ) << std::endl;
  std::cout<<"add : " << test.compute_( 5, 4, d, &D::multiply_ ) << std::endl;

使用 lambda 的示例:

#include <iostream>
#include <functional>

class D

public:
  D(int v ) : classVar_(v)
  int add_(int a, int b)return (a+b+classVar_);
  int multiply_(int a, int b)return (a*b+classVar_);
private:
  int classVar_;
;

class test 
public:

int compute_(int a, int b, std::function< int(int,int) > f)

   int c=0;
   // Some complex loops 
   c += f(a,b);
   // 
   return c;


;

int main()

  test test;
  D d(1);

  std::cout<<"add : " << test.compute_( 5, 4, [&d](int a, int b) return d.add_(a,b);  ) << std::endl;
  std::cout<<"add : " << test.compute_( 5, 4, [&d](int a, int b) return d.multiply_(a,b);  ) << std::endl;

【讨论】:

可以合并testD这两个类吗? @Nico 是的,您可以合并它们。我将它们分开,因为它使示例更通用。

以上是关于如何最好地将方法传递给同一类的方法的主要内容,如果未能解决你的问题,请参考以下文章

如何正确地将文本文件传递给 NSFileManager

如何正确地将页面属性传递给局部视图?

在 C# 中如何正确地将 int 数组传递给函数

如何正确地将单击按钮属性值传递给表单提交事件?

如何正确地将带有空格的$ string传递给grep

如何正确地将参数传递给 Django 中的基于类的视图实例?