2

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

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

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

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

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

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

4

3 回答 3

1

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

大多数算法的 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实例。只需根据您是否希望从课堂外实际访问状态来选择。

于 2009-10-29T08:26:47.913 回答
0

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

于 2009-10-29T08:46:11.820 回答
0

基于模板的解决方案。

#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;
}
于 2009-10-29T10:13:31.517 回答