比較した2つの手法の長所/短所は何ですか?そしてもっと重要なのは、なぜ、いつ一方を他方よりも使用する必要があるのかということです。それは個人的な好み/好みの問題ですか?
私の能力の限りでは、私の質問に明示的に対処する別の投稿は見つかりませんでした。ポリモーフィズムおよび/または型消去の実際の使用に関する多くの質問の中で、以下が最も近いように思われるか、そう思われましたが、それは私の質問にも実際には対応していません。
私は両方のテクニックをよく理解していることに注意してください。この目的のために、以下に簡単で自己完結型の実用的な例を示します。これは、不要と思われる場合は削除できます。ただし、この例では、私の質問に関して2つの手法が何を意味するのかを明確にする必要があります。私は命名法について議論することに興味がありません。また、コンパイル時と実行時のポリモーフィズムの違いは知っていますが、これは質問に関連しているとは思いません。パフォーマンスの違いがある場合は、パフォーマンスの違いにはあまり関心がないことに注意してください。しかし、パフォーマンスに基づいてどちらか一方に印象的な議論があった場合、私はそれを読みたいと思います。特に、2つのアプローチのいずれかでのみ実際に機能する具体的な例(コードなし)について聞きたいと思います。
以下の例を見ると、主な違いの1つはメモリ管理です。これは、ポリモーフィズムの場合はユーザー側に残り、型消去の場合は参照カウント(またはブースト)が必要になります。とは言っても、使用シナリオによっては、ポリモーフィズムの状況が改善される可能性があります。たとえば、ベクトル(?)でスマートポインターを使用することで状況が改善される可能性がありますが、任意の場合、これは実用的ではないことがよくあります(?)。型消去を支持する可能性のある別の側面は、共通のインターフェースの独立性かもしれませんが、なぜそれが利点になるのでしょうか(?)。
以下に示すコードは、以下のすべてのコードブロックを単一のソースファイルに入れるだけで、MS VisualStudio 2008でテスト(コンパイルおよび実行)されました。Linuxではgccでもコンパイルする必要があります。そうしないと、理由がわからないので(?):-)わかりやすくするために、ここでコードを分割/分割しました。
これらのヘッダーファイルで十分ですよね(?)。
#include <iostream>
#include <vector>
#include <string>
ブースト(または他の)依存関係を回避するための単純な参照カウント。このクラスは、以下のtype-erasure-exampleでのみ使用されます。
class RefCount
{
RefCount( const RefCount& );
RefCount& operator= ( const RefCount& );
int m_refCount;
public:
RefCount() : m_refCount(1) {}
void Increment() { ++m_refCount; }
int Decrement() { return --m_refCount; }
};
これは単純な型消去の例/図です。次の記事から一部コピーおよび変更されました。主に私はそれをできるだけ明確でわかりやすくするように努めました。 http://www.cplusplus.com/articles/oz18T05o/
class Object {
struct ObjectInterface {
virtual ~ObjectInterface() {}
virtual std::string GetSomeText() const = 0;
};
template< typename T > struct ObjectModel : ObjectInterface {
ObjectModel( const T& t ) : m_object( t ) {}
virtual ~ObjectModel() {}
virtual std::string GetSomeText() const { return m_object.GetSomeText(); }
T m_object;
};
void DecrementRefCount() {
if( mp_refCount->Decrement()==0 ) {
delete mp_refCount; delete mp_objectInterface;
mp_refCount = NULL; mp_objectInterface = NULL;
}
}
Object& operator= ( const Object& );
ObjectInterface *mp_objectInterface;
RefCount *mp_refCount;
public:
template< typename T > Object( const T& obj )
: mp_objectInterface( new ObjectModel<T>( obj ) ), mp_refCount( new RefCount ) {}
~Object() { DecrementRefCount(); }
std::string GetSomeText() const { return mp_objectInterface->GetSomeText(); }
Object( const Object &obj ) {
obj.mp_refCount->Increment(); mp_refCount = obj.mp_refCount;
mp_objectInterface = obj.mp_objectInterface;
}
};
struct MyObject1 { std::string GetSomeText() const { return "MyObject1"; } };
struct MyObject2 { std::string GetSomeText() const { return "MyObject2"; } };
void UseTypeErasure() {
typedef std::vector<Object> ObjVect;
typedef ObjVect::const_iterator ObjVectIter;
ObjVect objVect;
objVect.push_back( Object( MyObject1() ) );
objVect.push_back( Object( MyObject2() ) );
for( ObjVectIter iter = objVect.begin(); iter != objVect.end(); ++iter )
std::cout << iter->GetSomeText();
}
私に関する限り、これはポリモーフィズムを使用してもほぼ同じことを達成しているようですが、そうではないかもしれません(?)。
struct ObjectInterface {
virtual ~ObjectInterface() {}
virtual std::string GetSomeText() const = 0;
};
struct MyObject3 : public ObjectInterface {
std::string GetSomeText() const { return "MyObject3"; } };
struct MyObject4 : public ObjectInterface {
std::string GetSomeText() const { return "MyObject4"; } };
void UsePolymorphism() {
typedef std::vector<ObjectInterface*> ObjVect;
typedef ObjVect::const_iterator ObjVectIter;
ObjVect objVect;
objVect.push_back( new MyObject3 );
objVect.push_back( new MyObject4 );
for( ObjVectIter iter = objVect.begin(); iter != objVect.end(); ++iter )
std::cout << (*iter)->GetSomeText();
for( ObjVectIter iter = objVect.begin(); iter != objVect.end(); ++iter )
delete *iter;
}
そして最後に、上記のすべてを一緒にテストします。
int main() {
UseTypeErasure();
UsePolymorphism();
return(0);
}