C++ 具有非虚拟成员的类的装饰器

C++ 具有非虚拟成员的类的装饰器,c++,decorator,C++,Decorator,我尝试使用decorator模式来实现通常的目的,以便能够在控制类层次结构的同时向类添加功能。我的困难源于这样一个事实:我的类A有一个成员basicVar和一个方法basicOp(),该方法处理一些未指定的基本功能,这些功能是必需的,但在任何派生类中都不会更改。因此,我宣布A为: class A { public: virtual void func() { /* Some default implementation */} void basicOp() { /* some basic

我尝试使用decorator模式来实现通常的目的,以便能够在控制类层次结构的同时向类添加功能。我的困难源于这样一个事实:我的类
A
有一个成员
basicVar
和一个方法
basicOp()
,该方法处理一些未指定的基本功能,这些功能是必需的,但在任何派生类中都不会更改。因此,我宣布A为:

class A {
public:
  virtual void func() { /* Some default implementation */}
  void basicOp() { /* some basic operation on basicVar*/}
private:
  int basicVar;
}
通过这种方式,派生类不需要实现
basicOp()
,对
basicOp()
的调用不会产生虚拟调用的开销。然后,我将装饰器基类实现为:

class ADecorator: public A{
protected:
  std::unique_ptr<A> _a;

public:
  ADecorator(std::unique_ptr<A> a): _a(std::move(a)){}
  void func(){ _a->func(); }
  void basicOp(){ _a->basicOp();}
}

被调用的方法将是
A::basicVar()
,它在
dec.basicVar
上操作,而不是
ADecorator::basicOp()
在dec.\u A.basicVar上操作,dec.basicVar是由decorator包装的对象的成员。这不会发生在
func()
上,因为它是虚拟的。通过将
basicOp()
声明为virtual,问题就解决了,但是声明一个virtual方法只是为了使使用decorator成为可能,这听起来像是在破坏接口

我很确信这一定是由于设计错误造成的,但我不能确切地指出是哪一个错误以及如何解决它。可能问题在于
a
中存在opf数据成员,或者实际上装饰器模式只用于所有方法声明为虚拟的类


提前感谢。

您是对的,
A
有状态与decorator用法不兼容。您有一个矛盾:您说过在派生类中永远不会更改
basicOp
,但是您有一个合理的派生类
ADecorator
,它确实想要更改它(通过将它转发到另一个对象)。如果
basicOp
可以在没有任何成员变量的情况下实现(例如,它只是一些虚拟调用的包装器),那么内部或外部对象执行对它的调用就不会有问题

解决这个问题的一种方法是
A
的那部分分离成
ConcreteA
并在
A

virtual ConcreteA& getConcrete()=0;

然后将
unique\u ptr
存储在decorator中,并适当地实现
getConcrete
;任何直接使用
ConcreteA
的人都可以拨打非虚拟电话。

受Davis Herring建议的启发,我将
A修改为:

class A {
public:
  A(): repr{std::make_shared<Representation>()} {}
  virtual void func() { /* Some default implementation */}
  void basicOp() { /* some basic operation on repr->basicVar*/}
protected:
  struct Representation{
    int basicVar;
  }
  A(const std::shared_ptr<Representation> &extRepr){repr = extRepr;};
  std::shared_ptr<Representation> Repr() {return repr;};
private:
  std::shared_ptr<Representation> repr;
}
class ADecorator: public A{
protected:
  std::unique_ptr<A> _a;

public:
  ADecorator(std::unique_ptr<A> a): A(a->Repr()), _a(std::move(a)){}
  void func(){ _a->func(); }
}
这样,装饰器和被装饰对象共享相同的
A
表示,因此
dec->basicOp()
对装饰器和被装饰对象进行操作

这看起来是一个相当棘手的问题,因为它使
a
的表示形式可用于派生类,因此
a
不能有真正的私有成员。更好的版本可以是:

class A {
public:
  A(): repr{std::make_shared<Representation>()} {}
  virtual void func() { /* Some default implementation */}
  void basicOp() { /* some basic operation on repr->basicVar*/ }
protected:
  class Representation{
    friend class A;
    int basicVar;
  }
  A(const std::shared_ptr<Representation> &extRepr){repr = extRepr;};
  std::shared_ptr<Representation> Repr() {return repr;};
private:
  std::shared_ptr<Representation> repr;
}

A类{
公众:
A():repr{std::make_shared()}{
虚拟void func(){/*某些默认实现*/}
void basicOp(){/*repr->basicVar上的一些基本操作*/}
受保护的:
类表示{
A级朋友;
int basicVar;
}
A(const std::shared_ptr&extRepr){repr=extRepr;};
std::shared_ptr Repr(){return Repr;};
私人:
std::共享报告;
}

我不知道这个实现是否有任何根本性的问题(除了明显的复杂性),但现在它对我来说是可行的。

开销可以忽略不计,如果它解决了另一个问题,不使用它是没有意义的。@MichaelChourdakis谢谢你的回答。我同意你的观点,但我认为将其虚拟化可能会让一些用户认为它应该在从
A
派生的类中被重写,而唯一要这样做的类是decorator。对我来说,这听起来是个糟糕的设计。因为
basicOp
不是抽象的,所以可以解释为函数可以被重写,但不必重写。除了良好的文档(“此函数不应被重写”)之外,您只需相信
A
的用户不会做任何坏事。如果他们这样做并抱怨,那么你可以说“嘿,我告诉过你这不是要被推翻的,你只能怪你自己!”:@Someprogrammerdude是的,我同意这是可行的,而且可能是可行的。不过,它闻起来并不是100%正常,所以在继续之前,我想知道我是否因为糟糕的设计选择而陷入了已知的陷阱。@NicolaMori我认为你不能也不应该解决这个问题。实际上,您希望
basicOp
具有虚拟行为,所以只需将其声明为虚拟;)非常感谢,我也有类似的想法,但由于我有限的编程技能,他们非常困惑。现在我想我明白了,我会在我的真实代码上试试你的建议,看看它是否符合我的需要,顺便说一句,很遗憾,这样一个常见的规则(“decorators不适合与有状态类一起使用”)没有出现在我读过的任何decorator教程中,这会节省我很多时间。
class A {
public:
  A(): repr{std::make_shared<Representation>()} {}
  virtual void func() { /* Some default implementation */}
  void basicOp() { /* some basic operation on repr->basicVar*/ }
protected:
  class Representation{
    friend class A;
    int basicVar;
  }
  A(const std::shared_ptr<Representation> &extRepr){repr = extRepr;};
  std::shared_ptr<Representation> Repr() {return repr;};
private:
  std::shared_ptr<Representation> repr;
}