При наследовании есть и другая связанная с копированием проблема. В одном месте руководства10
по языку Си++ недвусмысленно заявлено: "конструкторы и функция operator=() не наследуются". Однако далее в этом же документе говорится, что существуют ситуации, в которых компилятор не может создать конструктор копии или функцию operator=(), которые бы корректно вызывались вслед за функциями базового класса. Так как нет практической разницы между унаследованной и сгенерированной функциями operator=(), которые ничего не делают, кроме вызова функции базового класса, то эта неопределенность вызвала много бед.
Я наблюдал два полностью несовместимых поведения компиляторов, столкнувшихся с этой дилеммой. Некоторые компиляторы считали правильным, чтобы сгенерированные компилятором конструкторы копий и функции operator=()
вызывались автоматически после конструкторов и функций operator=()
базового класса (и вложенного объекта).11 Это как раз тот способ, который, по мнению большинства, реализуется языком программирования. Другими словами, со следующим кодом проблем не будет:
class base
{
public:
base( const base &r );
const base &operator=( const base &r );
};
class derived : public base
{
string s;
// нет операции operator=() или конструктора копии
};
derived x;
derived y = x; // вызывает конструктор копии базового класса
// для копирования базового класса. Также
// вызывает
конструктор копии строки для
// копирования поля s.
x = y; // вызывает функцию базового класса operator=() для
// копирования базового класса. Также вызывает
// строковую
функцию operator=() для копирования поля s.
Если бы все компиляторы работали таким образом, то проблемы бы не было. К несчастью, некоторые компиляторы принимают ту самую директиву "не наследуются" за чистую монету. Только что представленный код не будет работать с этими компиляторами. В них сгенерированные компилятором конструктор копии и функция