13.7.4 Неявная операция копирующего присваивания для виртуальных баз
Когда базовый класс является виртуальным, только один подобъект базового класса принадлежит каждому полному объекту. Кроме того, конструкторы и деструкторы вызываются только один раз и вызываются из класса, наиболее производного от базового. Однако поведение таких объектов при присваивании не определено. Например:
struct Base{
char *name;
Base(char *n) : name(strdup(n)){}
Base& operator= (const Base& other){
free (name);
name = strdup (other.name);
}
};
struct A:virtual Base{
int val;
A():Base("A"){}
};
struct B:virtual Base{
int bval;
B():Base("B"){}
};
struct Derived:public A, public B{
Derived():Base("Derived"){}
};
void func(Derived &d1, Derived &d2)
{
d1 = d2;
}
Стандарт C++ определяет, что «Base::Base» вызывается только один раз при создании или копирующем создании объекта Derived. Не определено, вызывается ли «Base::operator=» более одного раза при вызове неявной операции копирующего присваивания для объектов Derived (как это происходит внутри «func» в примере).
G++ реализует «интуитивный» алгоритм для копирующего присваивания: присвоить все прямые базы, затем присвоить все члены. В этом алгоритме подобъект виртуальной базы может встречаться более одного раза. В примере копирование происходит в следующем порядке: «val», «name» (через strdup), «bval», и «name» ещё раз.
Если код приложения полагается на копирующее присваивание, пользовательский оператор копирующего присваивания устраняет любые неопределённости. С таким оператором приложение может определить, нужно ли и как присваивать подобъект виртуальной базы.
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-5.5.0/gcc/Copy-Assignment.html