仮想コンストラクタイディオムには、仮想関数を使用して新しいオブジェクトまたはオブジェクトのコピーを返す仮想関数があります。ただし、これらの仮想関数をポリモーフィックな方法で呼び出すには、実際のコンストラクターを使用してそのクラスのオブジェクトを作成する必要があります。
デザインパターンのコンテキストでは、オブジェクト作成のポリモーフィックな方法を使用する前に、クライアントがオブジェクトのタイプを認識していることを意味しますか?
仮想コンストラクタイディオムには、仮想関数を使用して新しいオブジェクトまたはオブジェクトのコピーを返す仮想関数があります。ただし、これらの仮想関数をポリモーフィックな方法で呼び出すには、実際のコンストラクターを使用してそのクラスのオブジェクトを作成する必要があります。
デザインパターンのコンテキストでは、オブジェクト作成のポリモーフィックな方法を使用する前に、クライアントがオブジェクトのタイプを認識していることを意味しますか?
クライアントは必ずしも具体的なタイプを知っている必要はありません。たとえば、次の階層について考えてみます。
struct Base
{
virtual ~Base();
virtual Base * clone() const = 0;
static Base * create(std::string const &);
// ...
};
struct A : Base { A * clone() const { return new A(*this); } /* ... */ };
struct B : Base { B * clone() const { return new B(*this); } /* ... */ };
struct C : Base { C * clone() const { return new C(*this); } /* ... */ };
Base * Base::create(std::string const & id)
{
if (id == "MakeA") return new A;
else return new C;
};
この場合、クライアントは次のように既存のオブジェクトを作成してコピーできます。
Base * p = Base::create("IWantB"); // or std::unique_ptr<Base> !
Base * q = p->clone();
どちらの場合も、クライアントはまたはの動的タイプを認識しませ*p
ん*q
。
class Base
{
public:
Base() { }
virtual ~Base() { }
// The "Virtual Constructor"
static Base *Create(int id);
// The "Virtual Copy Constructor"
virtual Base *Clone() = 0;
};
Base *Base::Create(int id)
{
if( id == 1 )
{
return new Derived1;
}
}
class Derived1 : public Base
{
public:
Derived1()
{
cout << "Derived1 created" << endl;
}
Derived1(const Derived1& rhs)
{
cout << "Derived1 created by deep copy" << endl;
}
~Derived1()
{
cout << "~Derived1 destroyed" << endl;
}
Base *Clone()
{
return new Derived1(*this);
}
};
あなたがするとき今メインに
void main()
{
cout << "Enter ID (1, 2 or 3): ";
cin >> input;
Base *pBase = Base::Create(input);
Base *pCopy = CreateCopy(pBase);
//Dont know what object is created but still access functions thru base pointer
}
Base *CreateCopy(Base *pBase)
{
return pBase->Clone();
}
クライアントは、継承するクラスのタイプを知る必要はありませんが、それでも何らかの関数を呼び出します。
クライアントが派生型を認識しない仮想コンストラクタイディオム。このイディオムの全体的な目的は、ベースポインタを介してオブジェクトのクローンを作成できるようにすることです。次に例を示します。
class base
{
public:
base* clone()
{
// NVI: implemented by derived classes.
do_clone();
}
protected:
virtual base* do_clone = 0;
};
class derived : public base
{
protected:
virtual derived* do_clone()
{
// Implementation. Note the return value is not base*.
}
};
詳細については、このACCUの記事を参照してください:http://accu.org/index.php/journals/522
最終的には、どこかでオブジェクトの具体的なタイプを知る必要があります。その詳細を非表示にするという考えは、制御の反転、または最近では依存性注入と呼ばれるパターンにつながります。
使用される具体的なタイプを認識しているプログラム全体の1つのコンポーネントを指定することを目的としています。次に、オブジェクトグラフを組み立てるのはこのコンポーネントの責任になります。他のコンポーネントは、依存関係をインターフェースとしてのみ取得し、構築時またはメソッドを介して渡されます。
C ++用の依存性注入の実装はいくつかあります。spring-cpp、autumnframework、およびdicppが思い浮かびます。私は自分でsauseと呼ばれるものを作成しました。これは、 guiceという名前のJavaフレームワークのスタイルをエミュレートします。