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