15.7.4 Неявное копирующее присваивание для виртуальных базовых классов
Если базовый класс является виртуальным, каждому полному объекту принадлежит только один подобъект этого базового класса. Кроме того, конструкторы и деструкторы вызываются только один раз — из наиболее производного класса. Однако поведение таких объектов при присваивании не определено. Например:
struct Base{
char *name;
Base(const char *n) : name(strdup(n)){}
Base& operator= (const Base& other){
free (name);
name = strdup (other.name);
return *this;
}
};
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++ реализует «интуитивный» алгоритм копирующего присваивания: присваивает все непосредственные базовые классы, а затем все поля. При этом алгоритме подобъект виртуального базового класса может быть обработан более одного раза. В примере копирование выполняется в следующем порядке: ‘name’ (через strdup), ‘val’, снова ‘name’ и ‘bval’.
Если код приложения полагается на копирующее присваивание, неопределённость устраняет пользовательский оператор копирующего присваивания. С таким оператором приложение может определить, будет ли присваиваться подобъект виртуального базового класса и каким образом.
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-15.3.0/gcc/Copy-Assignment.html