Предоставленный реализацией конструктор копирования и оператор присваивания

StackOverflow https://stackoverflow.com/questions/4338073

Вопрос

У меня есть небольшая путаница относительно ситуаций, когда реализация (компилятор) не будет предоставлять конструктор копирования и оператор присваивания копирования.

  1. Когда мы объявляем ctor копирования и / или оператор присваивания копирования в нашем классе.
  2. Некоторые говорят, когда мы производны от класса, у которого есть частный ctor копирования и / или оператор присваивания копирования.

Меня немного смущает вторая ситуация, это именно вторая ситуация.
a) Реализация не будет объявлять их для вас, поэтому вы получите ошибку во время компиляции.
или
б) Реализация объявит и определит их, но когда определенная компилятором реализация попытается найти метод базового класса, мы получим ошибку времени компиляции.

Вчера у меня было интервью, я сказал, что это (b) происходит, но интервьюер не согласен, он говорит, что это (a).

Я попытался скомпилировать следующий код как на Microsoft C / C ++ 14.00, так и на gcc 4.4.5

struct A
{
private:
  A& operator = ( const A& );
};

struct B : A
{
};


int main()
{
  B b1;
  B b2;
  b1 = b2;

  return 0;
}

Выходные данные компилятора Microsoft

ctor01.cpp(9) : error C2248: 'A::operator =' : cannot access private member declared in class 'A'
ctor01.cpp(4) : see declaration of 'A::operator ='
ctor01.cpp(2) : see declaration of 'A'
This diagnostic occurred in the compiler generated function 'B &B::operator =(const B &)'

выходные данные компилятора gcc

Ctor01.cpp: In member function ‘B& B::operator=(const B&)’:
Ctor01.cpp:4: error: ‘A& A::operator=(const A&)’ is private
Ctor01.cpp:8: error: within this context
Ctor01.cpp: In function ‘int main()’:
Ctor01.cpp:15: note: synthesized method ‘B& B::operator=(const B&)’ first required here 

Поэтому я думаю, что реализация объявит и определит его, но когда определенная компилятором реализация попытается найти метод базового класса, мы получим ошибку времени компиляции.Поправьте меня, если я ошибаюсь.

Это было полезно?

Решение

Что касается конструктора копирования, то это то, что говорится в стандарте (12.8 / 7). :

Программа является некорректной, если класс , для которого конструктор копирования неявно определенный имеет:

  • нестатический элемент данных типа class (или его массив) с недоступной или неоднозначной копией конструктора, или
  • базовый класс с недоступной или неоднозначной копией конструктор.

Что касается оператора присваивания копии (12.8/12) :

Программа является некорректной, если класс , для которого используется оператор присваивания копирования , является неявно определенный имеет:

  • нестатический элемент данных типа const, или
  • нестатический элемент данных ссылочного типа, или
  • нестатический элемент данных типа class (или его массив) с недоступным оператором присваивания копии, или
  • базовый класс с недоступным оператором присваивания копии.

Как компилятор сообщает об ошибке, или как это происходит на самом деле падает с моей точки зрения, это в значительной степени неуместно.

Тем не менее, я действительно считаю, что ответ (b), вероятно, Еще правильный :объявлено назначение копии базового класса, и оно недоступно.Производный класс неявно имеет объявленный скопировать назначение, которое компилятор попытается выполнить определить если используется, что делает программу плохо сформированной.

Другие советы

Класс будет иметь конструктор копирования и оператор присваивания копирования неявно объявленный если нет заявленной пользователем версии ни того, ни другого.Так происходит всегда.

Упрощенно говоря, реализация будет неявно определить это только в том случае, если они действительно используются.Если, когда реализация попытается определить их, неявное определение будет неверно сформировано (напримердля копирования-присваивания класс содержит ссылочный элемент или постоянный элемент, или для конструктора копирования базовый элемент или элемент имеет закрытый конструктор копирования), тогда программа неправильно сформирована.

Программа все еще может быть действительной, если она содержит классы, которые неявно имеют объявленный копируйте конструкторы и копируйте операторы присваивания, которые не могут быть определены неявно до тех пор, пока это не приведет к их фактическому определению путем их использования или не заставит их использоваться.

Ваш случай (b) более точен.

Стандарт C ++ 03 12.8p10

Если в определении класса явно не объявлен оператор присваивания копии, объявляется один из них неявно.

И 12.8p12

Неявно объявленный оператор присваивания копии является неявно определенный когда объекту его типа класса присваивается значение его типа класса или значение типа класса, производного от его типа класса.Программа является некорректно сформированной, если класс, для которого неявно определен оператор присваивания копирования, имеет:

  • нестатический элемент данных const тип, или
  • нестатический элемент данных ссылочного типа, или
  • нестатический элемент данных типа class (или его массив) с недоступным оператором присваивания копии, или
  • базовый класс с недоступным оператором присваивания копии.

Соответствующие требования для неявно определенных конструкторов копирования, конструкторов по умолчанию и деструкторов имеют схожие формулировки.

Указание на то, что методы существуют, даже если их определения будут незаконными, проясняет некоторые моменты, касающиеся разрешения перегрузки.Например,

class A {
private:
  A& operator=(const A&);
};

class B : public A {
public:
  operator int() const;
  B& operator=(int);
};

void f(B& b1, const B& b2)
{ b1 = b2; }

является незаконным, поскольку неявно заявленный B::operator=(const B&) это лучшая перегрузка, но неявное определение неверно сформировано.Без этого объявления вы могли бы подумать, что компилятор должен неявно преобразовывать b2 Для int а затем назначьте это для b1.

Я думаю, что различие между ними зависит от деталей вашей конкретной реализации (и не имеет большого значения).Как бы то ни было, Комо дает это:

"ComeauTest.c", line 7: error: "A &A::operator=(const A &)" (declared at line 4) is
          inaccessible
  struct B : A
             ^
          detected during implicit generation of "B &B::operator=(const B &)"
                    at line 16

1 error detected in the compilation of "ComeauTest.c".

Итак, в этом компиляторе он обнаруживает ошибку "во время" неявной генерации оператора присваивания B.Другими словами, он пытается сгенерировать его и обнаруживает, что не может.Обнаруживает ли он это при записи или при просмотре A непосредственно это на самом деле не имеет значения.

Вот что происходит :

struct A
{
private:
  A& operator = ( const A& );
};

struct B : A
{
  B& operator = ( const B& other )
  {
    A::operator=( other );
    return *this;
  }
};


int main()
{
  B b1;
  B b2;
  b1 = b2;

  return 0;
}

Оператор по умолчанию= пытается вызвать A::operator=, который является закрытым.

Стандарт, похоже, с вами согласен.Цитирую из текущего проекта:

§12.8/8:

Если в определении класса явно не объявлен конструктор копирования и нет объявленного пользователем конструктора перемещения , конструктор копирования неявно объявлен как установленный по умолчанию (8.4).

§12.8/12:

Конструктор копирования / перемещения по умолчанию для класс X определяется как удаленный (8.4.3), если X имеет:[…]

  • прямой или виртуальный базовый класс B, который не может быть скопирован / перемещен, поскольку разрешение перегрузки (13.3), применяемое к соответствующему конструктору B, приводит к неоднозначности или функции , которая удаляется или недоступна из конструктор по умолчанию [...]

Таким образом, синтезированный конструктор копирования объявлен и определен, но определен как удаленный.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top