1

デコレータ パターンを使用しようとすると問題が発生します。コンストラクターは、デバッグ用にアドレスを出力しています。以下でコンパイル:

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 は _decorated メンバーとして初期化されていない値 _outside._decorated を持ちます。これは、コピー コンストラクターが呼び出されたことを意味します。クラス Decorator にコピー コンストラクター コードを追加すると、次のようになります。

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

それは実際にそれを呼び出します。

Group コンストラクターの 2 行目を

: 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 から Group を派生させ、コピー コンストラクターを呼び出さない方法はありますか?

4

1 に答える 1

1

私の問題は、Decorator(_outside) がコピー コンストラクターを呼び出しているように見えることです。

あなたはそれが何をすることを期待していますか?

DecoratorOutside受け取るコンストラクターがないため、適格なコンストラクターは次のいずれかです。

Decorator(const Base&)

または暗黙的に定義されたコピー コンストラクター:

Decorator(const Decorator&)

最初のオプションには からOutsideへの暗黙的な変換が含まれますがBase、2 番目のオプションには からOutsideへのDecorator変換が含まれます。OutsideBaseDecoratorBase

発見したように、必要なコンストラクターを呼び出すには、目的の変換を明示的に行う必要があります。

Decorator(static_cast<Base&>(_outside))

渡す型は実際にはであるため、これは必要です。Decoratorもちろん、コピー コンストラクターが優先されます。

もう 1 つの解決策は、適切に制約されたテンプレートなど、コピー コンストラクターの代わりに使用されるコンストラクターを追加することです。

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

これは、から派生しBaseたものの、a ではなく、aBaseではないものすべてに使用されます。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)
  { }
于 2013-04-01T21:13:37.083 に答える