Ниже приведен простой пример того, как базовые методы доступны в производном классе:
struct Base {
void foo ();
Base& operator = (const Base&);
};
struct Derived : Base {
// ...
};
int main () {
Derived d1, d2;
d1.foo(); // calls Base::foo
d1 = d2; // calls Base::operator =
}
Если я добавлю ниже заявления в теле Derived
чтобы скрыть оба метода, …
struct Derived : Base {
//...
private: // hide the below method for `Derived` objects
using Base::foo;
using Base::operator =;
}
… тогда Base::foo()
успешно скрыт (становится недоступным).
Но Base::operator =
по-прежнему остается доступной!!
d1.foo(); // error
d1 = d2; // ok !!
То же самое происходит и для других операторов.. Вот демо с g ++.
Не должны ли правила доступности (применяются из-за using
ключевое слово) применяются к методам и операторам одинаково?
Если нет, то в чем смысл заявления: using operator =;
это просто игнорируется компилятором?
Обновить:
Derived::operator =
, Это неправильно, потому что он используетBase::operator =
, private
наследство, то Base::foo()
автоматическиusing
). Но не влияет на Base::operator =
,Обратите внимание, что я не хочу, чтобы решение «как это скрыть». Но хотелось бы понять с языковой точки зрения, почему операторы не скрыты как другие методы.
Компилятор сгенерирует значение по умолчанию operator=
для производного класса, и это неявное Derived::operator=
в свою очередь вызывает Base::operator=
внутренне.
Чтобы избавиться от этого, нам нужно отключить operator=
в явном виде:
struct Derived : Base {
private: Derived& operator = (const Derived&); // C++03 way
};
struct Derived : Base {
Derived& operator = (const Derived&) = delete; // C++11 way
};
Обновить:
Моей первой мыслью было, что компилятор может генерировать свой собственный Derived :: operator = по умолчанию. Это неправильно, потому что он используетBase::operator =
, То же самое относится и к другим операторам.Если я использую частное наследство, то
Base::foo()
автоматически скрывается (даже без использования). Но не влияет наBase::operator =
, это все еще работает.
Ваш первый хотя был правильным. Вы не объявили оператор присваивания копии, поэтому он был объявлен неявно для вас. Ты тогда ODR-использовал этот неявно объявленный оператор присваивания копии, поэтому компилятор предоставил неявно определенный оператор присваивания копии. Неявно определенный оператор присваивания копии структуры или класса выполняет пошаговое присваивание копии базовых классов класса, а затем его нестатических членов-данных.
Этот неявно определенный оператор присваивания копии является членом класса. Неважно, что вы спрятали конструктор копирования базового класса во внешний мир через using
или посредством частного наследования, потому что этот оператор присваивания базового класса видим для этого неявно определенного оператора присваивания копии.