如何在 c++ 中实现多个类的公共函子

发布于 2024-08-09 11:00:36 字数 508 浏览 4 评论 0原文

假设你有两个(或更多)带有私有成员向量的类:

class A {  
private:  
 std::vector<X> priv_vec;  
public:  
 //more stuff  
}  

class B {  
private:  
 std::vector<Y> priv_vec;  
public:  
 //more stuff  
}  

并且你有一个函子类,它有一个状态并作用于通用向量(对元素进行排序或计数或类似的操作)。函子的状态由函子正在处理的第一个向量初始化。如果函子稍后应用于另一个向量,它将根据状态改变其行为(以相同的方式排序或在与第一个向量一样多的元素之后修剪第二个向量,等等)

实现这样的最佳方法是什么函子(设计模式或函数式接口?)而不将私有向量暴露给其他类或类的用户?

例如: 用户希望使用 A 类的对象初始化此函子,然后将这个初始化的函子用于 B 类的一个或多个对象。用户不能(也不应该)直接将私有向量用作函数-函子的参数。

suppose you have two (or more) classes with private member vectors:

class A {  
private:  
 std::vector<X> priv_vec;  
public:  
 //more stuff  
}  

class B {  
private:  
 std::vector<Y> priv_vec;  
public:  
 //more stuff  
}  

and you have a functor-class which has a state and works on a generic vector (does sorting or counts elements or something like that). The state of the functor is initialized by the first vector the functor is working on. If the functor is applied to another vector later, it will change its behavior depending on the state (sorts in the same way or trims the second vector after as many elements as the first one, etc)

What is the best way to implement such a functor (desgin-pattern or functional interface?) without exposing the private vectors to the other classes or the user of the classes?

for example:
The user would like to initialize this functor with an object of class A and then use this initialized functor for one or more objects of class B. The user isn't able (and shouldn't be) to use the private vectors directly as function-arguments for the functor.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

花伊自在美 2024-08-16 11:00:36

嗯,首先,要注意函子中的状态。

大多数算法的 STL 实现可能会复制函子,因此您通常必须在外部结构中提取状态。

现在,对于函子的应用,很简单:让您的类声明一个模板成员函数!

class A
{
public:
  template <class Functor>
  Functor Apply(Functor f);

private:
};

class B
{
public:
  template <class Functor>
  Functor Apply(Functor f);
};

// Usage
MyFunctor f;
A a;
B b;
b.Apply(a.Apply(f));

至于函子,如果您需要状态:

// Alternative 1
class FunctorState {};

class Functor
{
public:
  Functor(FunctorState& state): m_state(state) {}

  // some operator()(...)

private:
  FunctorState& m_state;
};

// Alternative 2
class Functor
{
  struct FunctorState {};
public:
  Functor(): m_state(new FunctorState) {}

  // some operator()(...)

private:
  boost::shared_ptr<FunctorState> m_state;
};

这样,Functor 的副本都指向同一个 FunctorState 实例。只需根据您是否希望从类外部实际访问状态进行选择即可。

Hum, first, beware on states in functors.

Most STL implementation of the algorithms may copy your functors around, therefore you generally have to extract the state in an outer structure.

Now, for the application of functors, well it is simple: have your classes declare a template member function!

class A
{
public:
  template <class Functor>
  Functor Apply(Functor f);

private:
};

class B
{
public:
  template <class Functor>
  Functor Apply(Functor f);
};

// Usage
MyFunctor f;
A a;
B b;
b.Apply(a.Apply(f));

As for the functor, if you need state:

// Alternative 1
class FunctorState {};

class Functor
{
public:
  Functor(FunctorState& state): m_state(state) {}

  // some operator()(...)

private:
  FunctorState& m_state;
};

// Alternative 2
class Functor
{
  struct FunctorState {};
public:
  Functor(): m_state(new FunctorState) {}

  // some operator()(...)

private:
  boost::shared_ptr<FunctorState> m_state;
};

This way, copies of the Functor all points to the same FunctorState instance. Just choose depending if you wish to actually access the state from outside the class or not.

川水往事 2024-08-16 11:00:36

看起来像是从 A 类对象导入策略并将其应用到 B 类对象的问题,唯一的区别是,所有这些都是在运行时完成的(如与典型的基于策略的设计相反)。这就引出了一个问题,这些策略是 A 类专有的,还是我们可以隔离它们并根据需要传递它们?这应该可以简化设计。

Looks like a problem of importing policies from an object of class A and applying them to objects of class B, the only difference being, all of this is done at runtime (as opposed to typical policy-based design). This begs the question, are these policies proprietary to class A or can we isolate them and pass them around as required? That ought to simplify the deisgn.

π浅易 2024-08-16 11:00:36

基于模板的解决方案。

#include <iostream>
#include <string>
#include <vector>

// Wraps up a vector of type T and exposes a
// simple interface to access it.
template <class T>
class A
{  
public:  
  A(const std::vector<T>& v) : priv_vec(v) { }
  virtual size_t count() const { return priv_vec.size(); }
  virtual T operator[](size_t index) const { return priv_vec[index]; }
private:  
  std::vector<T> priv_vec;  
};  

// A sample functor with state.
// The state is the size and current index of the vector object.
class Functor
{
public:
  Functor() : _size(0), _index(0) { }

  // Prints the element at the current index.
  // If the index exceeds size, it is reset to 0.
  template <class T>
  void operator()(const A<T>& b)
  {
    if (_size == 0) _size = b.count();
    if (_index >= _size) _index = 0;
    std::cout << b[_index++] << '\n';
  }

private:
  size_t _size;
  size_t _index;
};

int
main()
{
  // Some tests.

  std::vector<int> int_vec;
  int_vec.push_back(1);
  int_vec.push_back(2);
  int_vec.push_back(3);
  A<int> a(int_vec);

  std::vector<std::string> str_vec;
  str_vec.push_back("aaaa");
  str_vec.push_back("bbbb");
  str_vec.push_back("cccc");
  A<std::string> b(str_vec);

  Functor f;
  f(a); // 1
  f(b); // bbbb
  f(a); // 3
  f(a); // 1
  f(a); // 2
  f(b); // cccc

  return 0;
}

A solution based on templates.

#include <iostream>
#include <string>
#include <vector>

// Wraps up a vector of type T and exposes a
// simple interface to access it.
template <class T>
class A
{  
public:  
  A(const std::vector<T>& v) : priv_vec(v) { }
  virtual size_t count() const { return priv_vec.size(); }
  virtual T operator[](size_t index) const { return priv_vec[index]; }
private:  
  std::vector<T> priv_vec;  
};  

// A sample functor with state.
// The state is the size and current index of the vector object.
class Functor
{
public:
  Functor() : _size(0), _index(0) { }

  // Prints the element at the current index.
  // If the index exceeds size, it is reset to 0.
  template <class T>
  void operator()(const A<T>& b)
  {
    if (_size == 0) _size = b.count();
    if (_index >= _size) _index = 0;
    std::cout << b[_index++] << '\n';
  }

private:
  size_t _size;
  size_t _index;
};

int
main()
{
  // Some tests.

  std::vector<int> int_vec;
  int_vec.push_back(1);
  int_vec.push_back(2);
  int_vec.push_back(3);
  A<int> a(int_vec);

  std::vector<std::string> str_vec;
  str_vec.push_back("aaaa");
  str_vec.push_back("bbbb");
  str_vec.push_back("cccc");
  A<std::string> b(str_vec);

  Functor f;
  f(a); // 1
  f(b); // bbbb
  f(a); // 3
  f(a); // 1
  f(a); // 2
  f(b); // cccc

  return 0;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文