Есть несколько классов с одинаковыми методами,
пожалуйста посоветуйте, как лучше применить шаблоны, чтобы
избежать повторного кода.
Пример методов классов:
// класс CDVLogin
CDVLogin & CDVLogin::operator=(const CDVLogin &r)
{
if (this != &r)
{
this->CDVLogin::~CDVLogin();
this->CDVLogin::CDVLogin(r);
}
return *this;
}
// класс CDVProxy
CDVProxy & CDVProxy::operator=(const CDVProxy &r)
{
if (this != &r)
{
this->CDVProxy::~CDVProxy();
this->CDVProxy::CDVProxy(r);
}
return *this;
}
Здравствуйте, Regard, Вы писали:
R>Пример методов классов:
R>R>// класс CDVLogin
R>CDVLogin & CDVLogin::operator=(const CDVLogin &r)
R>{
R> if (this != &r)
R> {
this->>CDVLogin::~CDVLogin();
this->>CDVLogin::CDVLogin(r);
R> }
R> return *this;
R>}
R>// класс CDVProxy
R>CDVProxy & CDVProxy::operator=(const CDVProxy &r)
R>{
R> if (this != &r)
R> {
this->>CDVProxy::~CDVProxy();
this->>CDVProxy::CDVProxy(r);
R> }
R> return *this;
R>}
R>
Обычно этот оператор через swap реализовывают
Здравствуйте, Regard, Вы писали:
Замечание 1:
Явный вызов конструктора не разрешен стандартом языка, так что вместо явного вызова нужно использовать размещающую форму new.
С учетом этого замечания можно соорудить вот это:
template <class D>
class auto_copy
{
protected:
void operator=(const auto_copy& rhs)
{
if (this != &rhs)
{
D* ptr = static_cast<D*>(this);
ptr->D::~D();
new (ptr)D(static_cast<const D&>(rhs));
}
}
~auto_copy() {}
};
class D1 : private auto_copy<D1>
{
int n_;
public:
D1(int n = 0) : n_(n) {}
D1(const D1& rhs) : n_(rhs.n_) {}
};
int main()
{
D1 d1(1), d2(2);
d1 = d2;
return 0;
}
В D1 operator= не определяется — все делается автоматически компилятором.
Замечание 2, более серьезное.
Саттер в "решении сложных задач" называет такой прием антиидиомой, и приводит некоторые аргументы в пользу этого высказывания.
Возможно, имеет смысл ознакомиться с этим пунктом и взвесить все "за" и "против" (это конечно если пока не читал)...
Здравствуйте, Bell, Вы писали:
B>Замечание 1:
B>Явный вызов конструктора не разрешен стандартом языка, так что вместо явного вызова нужно использовать размещающую форму new.
B>С учетом этого замечания можно соорудить вот это:
<>
B>В D1 operator= не определяется — все делается автоматически компилятором.
B>Замечание 2, более серьезное.
B>Саттер в "решении сложных задач" называет такой прием антиидиомой, и приводит некоторые аргументы в пользу этого высказывания.
B>Возможно, имеет смысл ознакомиться с этим пунктом и взвесить все "за" и "против" (это конечно если пока не читал)...
Действительно, антиидиома.
1) Если уж стоит задача унификации кода копирования и копирующего присваивания, то, может быть, лучше сделать наоборот:
class Foo
{
public:
Foo(const Foo& src)
// все члены должны быть DefaultConstructible
// либо инициализируем их по-простому
{
*this = src; // а здесь выполняем присваивание
}
Foo& operator=(const Foo& rhs)
{
// много содержательной и нетривиальной работы
...
...
...
return *this;
}
};
2) На ровном месте получаем кучу приключений
Действительно: пусть
class Foo
{
foo_members;
public:
virtual ~Foo() {}
Foo& operator=(const Foo& rhs)
{
placement_delete(this);
placement_new(this, rhs); // (1)
return *this;
}
};
class Bar : public Foo
{
bar_members;
public:
// явно или неявно определённый оператор.
Bar& operator=(const Bar& rhs)
{
(Foo&)(*this) = (const Foo&)rhs;
bar_members = rhs.bar_members; // (2)
}
};
Летит к чертям устойчивость к исключениям. Если в (1) будет брошено исключение, объект останется не просто в несогласованном состоянии (что, конечно, неприятно), а в разрушенном.
Невозможно наследоваться по-дефолтному. Перед (2) оказывается разрушенным весь объект Bar, а не только его база Foo.
... << RSDN@Home 1.2.0 alpha rev. 655>>