Каковы преимущества/недостатки двух методов в сравнении? И что еще более важно: зачем и когда нужно использовать друг друга? Это только вопрос личного вкуса/предпочтения?
В меру моих способностей, я не нашел другого сообщения, которое явно затрагивает мой вопрос. Среди многих вопросов, касающихся фактического использования полиморфизма и/или стирания стилей, кажется, что это самое близкое, или, похоже, это похоже, но на самом деле оно не касается и моего вопроса:
С++ - & CRTP. Тип стирания и полиморфизм
Пожалуйста, обратите внимание, что я очень хорошо понимаю обе методики. С этой целью я предоставляю простой, самостоятельный, рабочий пример ниже, который я с удовольствием удаляю, если это кажется ненужным. Однако на этом примере следует уточнить, что означают два метода в отношении моего вопроса. Мне не интересно обсуждать номенклатуры. Кроме того, я знаю разницу между полиморфизмом компиляции и времени выполнения, хотя я бы не счел это актуальным для вопроса. Обратите внимание, что мой интерес меньше в показателях производительности, если они есть. Однако, если бы был какой-то яркий аргумент для того или другого, основанного на производительности, мне было бы любопытно его прочитать. В частности, я хотел бы услышать о конкретных примерах (без кода), которые действительно будут работать только с одним из двух подходов.
В приведенном ниже примере одним из основных отличий является управление памятью, которое для полиморфизма остается на стороне пользователя, а для стирания стилей аккуратно спрятано, требуя некоторого подсчета ссылок (или повышения). Сказав, что в зависимости от сценариев использования ситуация может быть улучшена для примера полиморфизма с помощью смарт-указателей с вектором (?), Хотя для произвольных случаев это может оказаться очень непрактичным (?). Другой аспект, потенциально в пользу стирания стилей, может быть независимостью от общего интерфейса, но почему именно это было бы преимуществом (?).
Код, приведенный ниже, был протестирован (скомпилирован и запущен) с MS VisualStudio 2008, просто поместив все следующие кодовые блоки в один исходный файл. Он также должен компилироваться с помощью gcc в Linux, или я надеюсь/предполагаю, потому что не вижу причин, почему не (?):-) Я разделил/разделил код здесь для ясности.
Эти заголовочные файлы должны быть достаточными, right (?).
#include <iostream>
#include <vector>
#include <string>
Простой подсчет ссылок, чтобы избежать повышения (или других) зависимостей. Этот класс используется только в примере стирания типа.
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);
}