名前付きコンストラクターと継承
-
22-08-2019 - |
質問
私は C++ フレームワークに取り組んでおり、自動メモリ管理を多数のコア クラスに適用したいと考えています。これまでのところ、私は次のような標準的なアプローチを持っています
class Foo
{
public:
static
shared_ptr<Foo> init()
{
return shared_ptr<Foo>(new Foo);
}
~Foo()
{
}
protected:
Foo()
{
}
};
// Example of use
shared_ptr<Foo> f = Foo::init();
ただし、Foo をサブクラス化すると、上記は壊れます。 init()
継承されても返されます shared_ptr<Foo>
のインスタンスへのポインタが含まれています Foo
.
これに対するエレガントな解決策を考えられる人はいますか?おそらく、クラスのインスタンスを(半)手動でラップすることに固執する必要があります shared_ptr
?これにより、新しい名前付きコンストラクターを宣言せずにパラメーター化されたコンストラクターを公開する機能も提供されます。
つまり。
template <typename T>
shared_ptr<T> make_shared(T* ptr)
{
return shared_ptr<T>(ptr)
}
// Example
shared_ptr<T>
f1 = make_shared(new Foo()),
f2 = make_shared(new Foo(1,2));
解決
私は、これが実現し理解していない、あなたは、単にのshared_ptrを宣言することによってよりも、このinit関数を使用して余分なメモリ管理を取得するためには表示されません。
int main( void )
{
shared_ptr<foo> a = foo::init();
shared_ptr<foo> b( new foo );
}
の違いは何ですか。 shared_ptrのはinitの中のメモリ管理ではなく、何かを提供しています。
他のヒント
私はこのような何かをしようとするだろう
template<class T>
class creator
{
public:
static shared_ptr<T> init()
{
return(shared_ptr<T>(new T));
}
};
class A : public creator<A>
{
};
class B : public A, public creator<B>
{
public:
using make_shared<B>::init;
};
// example use
shared_ptr<A> a = A::init();
shared_ptr<B> b = B::init();
しかし、これは必ずしもあなたが提案したスタンドアロンのテンプレートに比べて、あなたの事を保存していません。
編集:私は前の回答を逃し、これは同じ考えのようです。
。目標はそれが不可能なクラスのユーザーが直接コンストラクタを呼び出し、唯一のshared_ptrのを返すルーチンを公開できるようにすることであると思われます。
あなたはこのパターンを適用する場合は、しかし、あなたはすべてのサブクラスでそれを複製する必要があります。サブクラスは、自動的にinitは()仮想メソッドではなく、オブジェクトなしで呼び出されているので、まだ、サブクラスのコンストラクタを呼ぶだろう)のinit()ので、INITを(「継承」することはできません。
私はいつものように公開コンストラクタを残して、ちょうど標準を使用します。
shared_ptr<X> x = new X();
これは、認知的負担を低く保つ読み取り可能で、かつ柔軟なまま。これはとにかく、我々は参照カウントのオブジェクトと私たちの会社でのプログラミング方法です。
どの程度...
template<typename Derived>
class Foo
{
public:
static shared_ptr<Derived> init()
{
return shared_ptr<Derived>(new Derived);
}
~Foo()
{
}
protected:
Foo()
{
}
};
class Bar : public Foo<Bar>
{
};
int _tmain(int argc, _TCHAR* argv[])
{
shared_ptr<Bar> b = Foo<Bar>::init();
return 0;
}
なぜそれから、必要なすべてのクラスを継承し、仮想デストラクタを共通のベースを導入していないし、単に新しいのでしょう?
これは、コンストラクタを非表示にすることで、shared_ptr
を使用してオブジェクトの作成を強制するために、一般的には良い考えではありません。私はまさにそれをした社内のlibでの作業ここでは個人的な経験から話しますよ。あなたは、人々は常に自分に割り当てられたオブジェクトをラップするようにしたい場合は、単にこれらの型のインスタンスを格納するすべての引数とメンバーがshared_ptr
またはweak_ptr
の代わりに、裸のポインタまたは参照を期待していることを確認してください。また、あなたはこれらの他のオブジェクトのメソッドのいずれかにenable_shared_from_this
ポインタを渡す必要がありますいくつかの点で、理由はすべてのオブジェクトが共有されているシステムでは、this
からこれらのクラスを派生する場合があります、そして、彼らは唯一に設計されているので、あなたのオブジェクトは、それが破壊されていないことを確認するには、no shared_ptr
を持っていない場合は、かなり悪い形にしている、internal_weak_this
を受け入れます。
あなたは、階層全体のすべてのタイプの静的ファクトリ関数を必要とします。
class Foo
{
public:
static shared_ptr< Foo > instantiate( /* potential arguments */ )
{
return shared_ptr< Foo >( new Foo( /* potential arguments */ );
}
// blah blah blah
};
class Bar : public Foo
{
public:
static shared_ptr< Bar > instantiate( /* potential arguments */ )
{
return shared_ptr< Bar >( new Bar( /* potential arguments */ );
}
// blah blah blah
};
あなたはまだ混乱を持っている場合は、、SourceForgeでCppCodeProviderを検索し、そのが行わ方法を確認してください。
ちなみに、大規模な C++ フレームワークでは、「自動メモリ管理」をコーダーから隠すのが一般的です。これにより、より短く単純なコードを作成できるようになります。たとえば、Qt では次のことができます。
QPixmap foo() {
QPixmap pixmap(10, 10);
return pixmap;
}
void bar() {
QPixmap a = foo(); // no copying occurs, internal refcount incremented.
QPixmap b = a; // ditto.
QPainter p(&b);
p.drawPoint(5, 5); // data can no longer be shared, so a copy is made.
// at this point 'a' is still unchanged!
p.end();
}
Qt の多くの機能と同様、これは Java オブジェクト モデルを模倣していますが、実装することでさらに進化しています。 コピーオンライト (それはそう呼んでいます) 暗黙的な共有)。これは、呼び出しに慣れていない C++ プログラマーにとって API の動作をそれほど驚かないようにすることを目的としています。 clone()
.
これは、 dポインタイディオム, 自動メモリ管理を提供するので一石二鳥です。 そして 実装をユーザーから隔離します (にきび).
ここで QPixmap の実際の実装を確認できます。 qpixmap.cpp, qpixmap.h.