Это не разрешено в Java:
class A {
public void method() {}
}
class B extends A {
private void method() {}
}
Это генерирует ошибку компиляции:
error: method() in B cannot override method() in A
attempting to assign weaker access privileges; was public
Однако это разрешено в C ++:
class A {
public:
virtual void method() {}
};
class B : public A {
private:
void method() {}
};
int main(void) {
A* obj = new B();
obj->method(); // B::method is invoked, despite it being private
}
Какая логика стоит за этим поведением в C ++?
Помните, что видимость method
разрешается чисто во время компиляции, C ++ не имеет понятия верификатора времени выполнения. То, что видит компилятор, является виртуальным A::method
, который не частный. Конкретная реализация является объявлено как private, но это имеет значение только тогда, когда эта реализация вызывается напрямую способом, видимым для компилятора, то есть, если вы пытаетесь получить к нему прямой доступ, вызывая ее через B
,
Логика этого иллюстрируется следующим случаем: представьте, если B
не унаследовал от A
публично, но в частном порядке — это разрешено в C ++ и используется, когда само наследование является деталью реализации, например, для stack
наследование класса от vector
, но не желая выставлять векторный интерфейс. В этом случае это будет особенность для B::method
быть недоступным, но A::method
работает нормально, даже если объект B
пример.
Как сказал Kerrek SB, здесь Java защищает вас от одного класса ошибок ценой удаления допустимых опций.
Что касается части виртуальных частных методов, то это позволяет реализовать Паттерн NVI, так что вы можете выполнять инвариантные проверки или настройку / разборку в ситуации, когда используется наследование.
Вот пример с блокировкой и проверкой постусловия:
class base {
public:
virtual ~base() = default;
// Calls the derived class' implementation in a thread-safe manner.
// @return A value greater than 42.
int function() {
std::lock_guard<std::mutex> guard(mutex);
auto result = function_impl();
assert(result > 42);
return result;
}
private:
std::mutex mutex;
virtual int function_impl() = 0;
};
class derived : public base {
private:
virtual int function_impl() override {
return 0; // Whoops! A bug!
}
};
В Java это может быть достигнуто с помощью защищенных методов, но это приведет к утечке деталей реализации к производным классам производных классов, что может быть нежелательным.
Что касается приватизации, то в противном случае общественные участники разойдутся, если кто-то вдруг сделает function_impl
публика в base
это не сломает производные классы. Я не говорю, что это очень хорошая идея, но C ++ обычно просто предполагает, что вы знаете, что делаете, поэтому это такой гибкий язык.