基于类型的类的引用计数实例

时间:2011-05-30 17:15:24

标签: c++ design-patterns

请考虑以下代码:

struct I
{
    SomeInternalState m_internalState;
};

struct S
{
    I * m_i;
    set_I (I * i)
    {
        m_i = i;
        makeSomeChangesToTheInternalStateOfI(m_i);
    }
};

struct S_1 : S { ... };
struct S_2 : S { ... };
...
struct S_n : S { ... };

可以创建S_1,... S_n的任意实例数,并且所有实例只会调用set_I()一次。

现在,我希望S_1,... S_nmakeSomeChangesToTheInternalStateOfI()的实例每个I每个S_x实例只需一次} ,以便我可以使用相同的set_I()实例从同一个类S_x的不同实例调用I,并确保{{1}的内部状态}只会在第一次调用时修改。

可能的决定是将一些调度表放入I,但我不能仅仅根据I实例的类型而不涉及任何手来考虑它的合理关键 - 为所有可能类型编写“运行时类型ID”常量S_x,... S_1

我该怎么做?

修改

我应该强调的要点:

1)一次可能有多个S_n个实例,而I - 类应该能够更改S_x的多个实例的状态,但仅限于每个实例一次。那就是:

I

在此片段中,I i1, i2; S_1 s1a, s1b; S_2 s2a, s2b; // all possible combinations: s1a.changeStateOfI(i1); s1b.changeStateOfI(i1); s2a.changeStateOfI(i1); s2b.changeStateOfI(i1); s1a.changeStateOfI(i2); s1b.changeStateOfI(i2); s2a.changeStateOfI(i2); s2b.changeStateOfI(i2); i1的状态只能通过i2的方法(通过S_1)更改一次,而{{1}更改一次}(通过s1a)。

2)我想,引用计数可以用来解决问题 - 没有必要确切地知道初始化发生了多少次,它足以知道它是否有效。

EDIT2

我已经将 n.m。的建议标记为答案,尽管我的最终解决方案略有不同。在这里,所以其他人也可以使用它:

S_2

n.m。的变体相比,差异在于我在这里使用了CRTP模式而不是枚举实例化,这也是我想要避免的。

2 个答案:

答案 0 :(得分:2)

您可以使用typeinfo作为密钥,但这不是一个好主意。您不应该计算程序中的类型。让我用一个简单的例子来解释。

假设您有Vehicle类型及其后代CarTruckBike。您可以为每个类调用一次函数。到现在为止还挺好。现在你需要一个完全不相关的原因来处理SUV,RacingCars,GarbageTrucks,Trikes,RedCars,ReddishCars和YellowishReddishWithGreenishTintCars。您对函数调用次数的决定应该与您关于引入或不为每种情况引入单独类的决定完全正交。

所以你需要一些东西来标记你的车辆是不同的或类似的,仅仅是为了每一堆类似物体调用你的功能一次。实现这一目标的一种方法是使用类模板和一组类型参数(任何类型的参数)。

class ChangerOfInternalStateOfI
{
  public:
    ChangerOfInternalStateOfI (I* i) { 
      makeSomeChangesToTheInternalStateOfI(i); 
    }
};

template <int n>
class S_N : public S
{
  public:
    S_N() {
       static ChangerOfInternalStateOfI changer;
    }
};

typedef S_N<1> S_1;
typedef S_N<2> S_2;

你可以使用enum代替int或typename,这并不重要。关键是你的所有ChangerOfInternalStateOfI都是不同的,因为它们属于不同的类,每个构造函数都将被调用一次。

答案 1 :(得分:1)

如果提到的静态数据成员 n.m。的方式不符合目标, 如何在I之前使用包含处理类型的集合呢? 由于type_info本身不是可比较的,因此是一个简单的包装器 type_info_用于以下代码中。 如果必须以多态方式完成类型检查(通过基类S), 需要运行时类型信息。 所以我将changeStateOfI设为virtual

#include <typeinfo>
#include <set>
using namespace std;

struct type_info_ {
  type_info const *t;
  type_info_( type_info const* t ) : t( t ) {}
  bool operator<( type_info_ const& x ) const { return t->before( *x.t ); }
};

struct I {
  set< type_info_ > types;

  void f( type_info const& t, char const* s ) {
    if ( types.insert( type_info_( &t ) ).second ) { puts( s ); }
  }
};

struct S {
  virtual void changeStateOfI( I& i, char const* s ) {
    i.f( typeid( *this ), s );
  }
};

struct S_1 : S {};
struct S_2 : S {};

int main() {
  I i1, i2;
  S_1 s1a, s1b;
  S_2 s2a, s2b;
  s1a.changeStateOfI(i1, "s1a i1");
  s1b.changeStateOfI(i1, "s1b i1");
  s2a.changeStateOfI(i1, "s2a i1");
  s2b.changeStateOfI(i1, "s2b i1");
  s1a.changeStateOfI(i2, "s1a i2");
  s1b.changeStateOfI(i2, "s1b i2");
  s2a.changeStateOfI(i2, "s2a i2");
  s2b.changeStateOfI(i2, "s2b i2");
}

上面的代码打印为s1a i1s2a i1s1a i2s2a i2 在我的环境中。