将成员动态添加到C ++类的解决方法

时间:2012-07-06 13:37:06

标签: c++ oop


我想知道你将如何解决这个问题:

我有一个班级Foo

class Foo
{
public:
    Foo()  {   }
    ~Foo() {   }
    float member1() { return _member1; }
private: 
    float _member1;
    // other members etc...
}

一个容器类,除其他外,它包含一个指向Foo实例的指针容器

class FooContainer
{
public:
   FooContainer() {   }
   ~FooContainer() {   }
   void addFoo(Foo* f) {_foos.push_back(f);}
private:
   boost::ptr_vector<Foo> _foos;
}

我的问题是:在运行时我需要向Foo“添加”新的(完全不同的)成员,具体取决于GUI的指令。我可以通过创建两个这样的“装饰器”来解决这个问题:

class Decorator1
{
public:
   int   alpha() { return _alpha; }
   float beta()  { return _beta; }
private:
   int _alpha;
   float _beta;
}

class Decorator2
{
typedef std::complex<float> cmplx;
public:
   cmplx  gamma() { return _gamma; }
   double delta()  { return _delta; }
private:
   cmplx  _gamma;
   double _delta;
}

然后我将创建两个不同的Foo实现:

class Foo1 : public Foo, public Decorator1 
{   }

class Foo2 : public Foo, public Decorator2 
{   }

并根据GUI命令使用每一个。但是,这样的更改会传播到我的所有代码中,并迫使我为使用Foo1Foo2的每个类创建两个不同的版本(例如,我必须创建FooContainer1和{ {1}})。

这种不太干扰的方法是创建

FooContainer2

并使用此代替class Bar: public Foo, public Decorator1, public Decorator2 { } 。在这种情况下,我只调用FooDecorator1所需的函数而忽略其他函数,但这似乎违背了良好的OOP技术。

有关此问题的任何建议吗?

4 个答案:

答案 0 :(得分:8)

为什么不使用这样的简单多态?

class Foo
{
public:
    Foo()  {   }
    virtual ~Foo() {   }
    float member1() { return _member1; }
private: 
    float _member1;
    // other members etc...
}

class Foo1 : public Foo
{   
    public:
   int   alpha() { return _alpha; }
   float beta()  { return _beta; }
private:
   int _alpha;
   float _beta;
}

class Foo2 : public Foo
{   
    typedef std::complex<float> cmplx;
public:
   cmplx  gamma() { return _gamma; }
   double delta()  { return _delta; }
private:
   cmplx  _gamma;
   double _delta;
}

class FooContainer
{
public:
   FooContainer() {   }
   ~FooContainer() {   }
   void addFoo(Foo* f) {_foos.push_back(f);}
private:
   boost::ptr_vector<Foo> _foos;
}

然后客户端代码无需更改。根据GUI命令,您可以创建Foo1或Foo2并将其添加到单个容器中。如有必要,可以使用Foo指针上的dynamic_cast转换为Foo1或Foo2。但是,如果您已正确编写客户端代码,则不需要这样做。

答案 1 :(得分:0)

基于策略的模板怎么样?有一个模板类Foo,它将类作为模板参数。然后,有两个调用装饰器方法的方法:

tempate <class Decor>
class Foo
{
public:
    Foo() : { __d = Decor()  }
    ~Foo() {   }
    float member1() { return _member1; }
    Decor::method1type decoratorMember1() { return __d.getValueMethod1();}
    Decor::method2type decoratorMember2() { return __d.getValueMethod2();}
private: 
    float _member1;
    Decor __d;
    // other members etc...
}

然后,在你的复杂装饰者中:

class Decor1 {
  typedef std::complex<float> method1type;
  typedef double method2type;
public:
  method1type getValueMethod1() {return _gamma}
  method2type getValueMethod2() {return _delta}
private:
  method1type _gamma;
  method2type _delta;
}

另一个相同。这样,您的Foo代码可以添加任何内容,即使它已经编译完毕。只需创建一个声明者类。而不是实例化Foo1,请执行以下操作:

Foo<Decor1> f;

答案 2 :(得分:0)

听起来你正在寻求处理mixin类型的功能。为此,您可以使用模板。在生成每个类的副本的意义上,这不是运行时,但它确实可以节省您的输入。

因此,对于每个装饰者,请执行以下操作:

template<class TBase> class Decorator1 : public TBase
{
public:
    void NewMethod();
}

然后你可以,例如:

Foo* d = new Decorator1<Foo1>(...);

当然,在运行时使这项工作的唯一方法是决定你要创建哪种类型。不过,您最终仍然使用FooFoo1Decorator1类型,因此您可以根据需要在它们之间进行投射/使用RTTI。

有关详情,请参阅this articlethis document


虽然我已经建议将其作为一种潜在的解决方案,但我个人很想接受多态性建议,如果可能的话 - 我认为这样可以更好,更容易维护代码,因为类实现的部分并不是分散的在所有地方使用mixins。只是我的两分钱 - 如果你认为它有效,那就去吧。

答案 3 :(得分:0)

类的基本概念是它被封装,因此在定义之后不能添加成员(尽管您可以使用多态并使用其他成员创建派生类,但它们无法通过原始类的指针:您必须将它们转换为派生的危险的),特别是在运行时。

所以在我看来,你的要求打破了OO编程的基本思想。这表明一个简单的解决方案:使用非成员函数。它们可以在任何时间定义,甚至可以在运行时定义(当您还需要编译它们时)。函数指针的开销与之前相同(当您需要指向新成员函数的指针时)。