Я пытаюсь реализовать идиому copy + swap для достижения безопасности с сильными исключениями через уровень абстракции и, хотя принцип ясен, как это часто бывает, дьявол кроется в деталях.
* 1002Скажем, у меня есть класс, который выглядит следующим образом:
class AConcreteType :
public ISomething,
public ISwappable
{
public:
// From ISwappable
void Swap( ISwappable& );
};
Теперь я могу сделать это в методе, который работает только с ISomething:
void AClass::DoSomething( ISomething& something )
{
// say there is a function that allows me to clone 'something'
// Probably it ought to go into an auto_ptr, but for clarity:
ISomething& somethingElse( clone( something ) );
// ... so that at the end, after doing stuff with somethingElese I can do
ISwappable& swappable1 = dynamic_cast<ISwappable&>( something );
ISwappable& swappable2 = dynamic_cast<ISwappable&>( somethingElse );
// ... I may want to check that the concrete types behind the interface are
// actually the same too with something like typeid, but I'll leave that out for clarity
swappable1.Swap( swappable2 );
}
, где
void AConcreteType::Swap( ISwappable& swappable )
{
AConcreteType& somethingConcrete = dynamic_cast<AConcreteType&>(swappable);
std::swap( *this, somethingConcrete );
}
Это все работает, так как все dynamic_casts находятся на ссылках, что является операцией, которая выдает, когда тип не поддерживается;это оставляет мои объекты в хорошем состоянии, так как обмен не происходит до самого конца.Но что меня не устраивает, так это то, что вызов swappable1.Swap (swappable2) все еще может генерировать (через тот же механизм dynamic_cast), и это было бы нелогичным для пользователя Swap, поскольку он, вероятно, ничего не ожидалбросить в этой точке.
Альтернативой, о которой я думал, был шаблон ISwappable, чтобы покончить с dynamic_cast внутри реализации Swap:
template< typename T >
class ISwappable
{
public:
virtual void Swap( T& ) = 0;
};
, чтобы его реализация была просто
class AConcreteType :
public ISomething,
public ISwappable<AConcreteType>
{
void Swap( AConcreteType& act ) { std::swap( *this, act ); }
};
Это позволяет не вызывать вызов Swap (и позволяет мне гарантировать, что два объекта действительно могут быть заменены во время компиляции), но теперь проблема заключается в том, что мне приходится иметь дело сконкретный тип внутри DoSomething, но у меня нет доступа к AConcreteType внутри этой функции.
Есть идеи?