c++ - 装饰器模式 - 我如何在初始化时不调用复制构造函数?

标签 c++ decorator copy-constructor

我在尝试使用装饰器模式时遇到问题。构造函数正在打印地址以进行调试。编译:

g++ -g -o go Decorator.cpp

我的简化代码:

#include <iostream>

class Base
{
public:
    Base()
    {
        std::cout << "Base created - this: " << this << std::endl;
    }
    virtual ~Base() {}
};

class Decorator : public Base
{
public:
    Decorator(const Base & decorated)
    : _decorated(&decorated)
    {
        std::cout << "Decorator created - this: " << this << " created - _decorated is " << _decorated << std::endl;
    }



    ~Decorator()
    {
        std::cout << "Decorator destroyed" << std::endl;
        std::cout << "  This: " << this << ", _decorated: " << _decorated << std::endl;
    }

private:
    const Base * _decorated;
};

class Inside : public Base
{
public:
    Inside()
    {   std::cout << "Inside created - this: " << this << std::endl;   }
};

class Outside : public Decorator
{
public:
    Outside(const Base & decorated)
    : Decorator(decorated)
    {
        std::cout << "Outside created - this: " << this << std::endl;
    }
};

class Group : public Decorator
{
public:
    Group()
    : Decorator(_outside)
    , _outside(_inside)
    {
        std::cout << "Group created - this: " << this << std::endl;
    }

    ~Group()
    {
        std::cout << "Group destroyed" << std::endl;
    }

private:
    Inside  _inside;
    Outside _outside;
};

int main()
{
    std::cout << "Hi there" << std::endl;

    Group g1;

    std::cout << "Done" << std::endl;
}

我的问题在 Group::Group() 中。我相信用未初始化的 _outside 初始化 Group 的 Decorator 基础部分很好 - Decorator 唯一想要的是指向对象的指针。我的问题是 Decorator(_outside) 似乎在调用复制构造函数,这是我不想要的。

gdb 优点:

Breakpoint 1, _fu0___ZSt4cout () at Decorator.cpp:63
63          Group g1;
(gdb) print g1
$1 = {<Decorator> = {<Base> = {_vptr.Base = 0x77c34e29},
    _decorated = 0x77c34e42}, _inside = warning: can't find linker symbol for vi
rtual table for `Inside' value
{<Base> = {
      _vptr.Base = 0x401a90}, <No data fields>},
  _outside = {<Decorator> = {<Base> = {_vptr.Base = 0x22ff58},
      _decorated = 0x401af6}, <No data fields>}}

我在 g1 的构造函数之前中断并将一些 _decorated 成员写入已知值以帮助调试。

(gdb) set g1._decorated = 0
(gdb) set g1._outside._decorated = 0xeeeeeeee
(gdb) print g1
$2 = {<Decorator> = {<Base> = {_vptr.Base = 0x77c34e29}, _decorated = 0x0},
  _inside = warning: can't find linker symbol for virtual table for `Inside' val
ue
{<Base> = {_vptr.Base = 0x401a90}, <No data fields>},
  _outside = {<Decorator> = {<Base> = {_vptr.Base = 0x22ff58},
      _decorated = 0xeeeeeeee}, <No data fields>}}
(gdb) n
Base created - this: 0x22ff34
Inside created - this: 0x22ff34
Base created - this: 0x22ff38
Decorator created - this: 0x22ff38 created - _decorated is 0x22ff34
Outside created - this: 0x22ff38
Group created - this: 0x22ff2c
65          std::cout << "Done" << std::endl;
(gdb) print g1
$3 = {<Decorator> = {<Base> = {_vptr.Base = 0x4042b8},
    _decorated = 0xeeeeeeee}, _inside = {<Base> = {
      _vptr.Base = 0x4042c8}, <No data fields>},
  _outside = {<Decorator> = {<Base> = {_vptr.Base = 0x4042d8},
      _decorated = 0x22ff34}, <No data fields>}}

在构造函数之后,g1._decorated 将_outside._decorated 的未初始化值作为其_decorated 成员,这意味着复制构造函数已被调用。如果我将复制构造函数代码添加到 Decorator 类:

Decorator(const Decorator & that)
{   std::cout << "Copy constructor - this: " << this << " - that: " << &that << std::endl;   }

它确实调用了它。

如果我将 Group 构造函数的第二行从

: Decorator(_outside)

: Decorator(static_cast<const Base &>(_outside))

然后运行 ​​gdb

Breakpoint 1, _fu0___ZSt4cout () at Decorator.cpp:63
63          Group g1;
(gdb) print g1
$1 = {<Decorator> = {<Base> = {_vptr.Base = 0x77c34e29},
    _decorated = 0x77c34e42}, _inside = warning: can't find linker symbol for vi
rtual table for `Inside' value
{<Base> = {
      _vptr.Base = 0x401a90}, <No data fields>},
  _outside = {<Decorator> = {<Base> = {_vptr.Base = 0x22ff58},
      _decorated = 0x401af6}, <No data fields>}}
(gdb) set g1._decorated = 0
(gdb) set g1._outside._decorated = 0xeeeeeeee
(gdb) print g1
$2 = {<Decorator> = {<Base> = {_vptr.Base = 0x77c34e29}, _decorated = 0x0},
  _inside = warning: can't find linker symbol for virtual table for `Inside' val
ue
{<Base> = {_vptr.Base = 0x401a90}, <No data fields>},
  _outside = {<Decorator> = {<Base> = {_vptr.Base = 0x22ff58},
      _decorated = 0xeeeeeeee}, <No data fields>}}
(gdb) n
Base created - this: 0x22ff2c
Decorator created - this: 0x22ff2c created - _decorated is 0x22ff38
Base created - this: 0x22ff34
Inside created - this: 0x22ff34
Base created - this: 0x22ff38
Decorator created - this: 0x22ff38 created - _decorated is 0x22ff34
Outside created - this: 0x22ff38
Group created - this: 0x22ff2c
65          std::cout << "Done" << std::endl;
(gdb) print g1
$3 = {<Decorator> = {<Base> = {_vptr.Base = 0x4042b8},
    _decorated = 0x22ff38}, _inside = {<Base> = {
      _vptr.Base = 0x4042c8}, <No data fields>},
  _outside = {<Decorator> = {<Base> = {_vptr.Base = 0x4042d8},
      _decorated = 0x22ff34}, <No data fields>}}

没有调用 Decorator 复制构造函数,一切似乎都很好。我不喜欢这个解决方案,因为它要求下游的每个类都记住这样做。

有没有什么方法可以从具有成员 Decorator 的 Decorator 派生组而不调用复制构造函数?

最佳答案

My problem is that Decorator(_outside) appears to be calling the copy constructor, which I DON'T want.

你希望它做什么?

Decorator 没有采用 Outside 的构造函数,因此符合条件的构造函数是:

Decorator(const Base&)

或隐式定义的复制构造函数:

Decorator(const Decorator&)

第一个选项涉及从 OutsideBase 的隐式转换,而第二个选项涉及从 OutsideDecorator,这是一个“更好”的转换,因为 OutsideBase 的转换“通过”Decorator 到达 Base.

正如您所发现的,要调用您想要的构造函数,您需要显式地进行所需的转换:

Decorator(static_cast<Base&>(_outside))

这是必要的,因为您传递的类型实际上是 Decorator 所以它当然更喜欢复制构造函数。

另一个解决方案是添加一个构造函数来代替复制构造函数,例如一个模板,适本地约束:

template<typename T>
  Decorator(const T& decorated, typename boost::enable_if<boost::is_base_of<T, Base> >* = 0)
  : _decorated(&decorated)
  { }

这将用于派生自 Base 但不是 Base 且不是 Decorator 的任何内容

在 C++11 中你可以让它更干净一些

template<typename T,
         typename Requires = typename std::enable_if<std::is_base_of<T, Base>::value>>
  Decorator(const T& decorated)
  : _decorated(&decorated)
  { }

关于c++ - 装饰器模式 - 我如何在初始化时不调用复制构造函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15751794/

相关文章:

c++ - 在创建 OpenCL 上下文之前设置线程亲和性会导致段错误

c++ - 如何正确地将 QList<QNetworkCookie> 转换为 QByteArray?

c++ - 如何向多个进程(但不是所有进程)广播或发送单个值?

Python 装饰器与 CLOS "around"方法的比较

多次调用的C++复制构造函数

c++ - 让子类在构造函数中接受对父类的引用

c++ - 锐化图像 - 访问邻近像素

python - 装饰生成器

python - 装饰器和类方法

c++ - 强制复制构造函数而不是移动构造函数