Предисловие
Название «Проблема снижения доступности подклассов по сравнению с функциями родительского класса в Java и C ++», кажется, более академическая, но это действительно проблема, которую легко игнорировать. Эта статья стремится уточнить разницу между этой проблемой в Java и C ++.
Во -первых, мы представим то, что является сокращением доступности подклассов по сравнению с охватом функции родительского класса ». Для наследования подклассы могут переопределить «виртуальные функции» родительского класса - хотя в Java нет термина, все функции Java можно рассматривать как виртуальные функции, поскольку все функции Java могут быть переопределены подклассами. Здесь мы заимствуем только значение термина «виртуальная функция» и не разбираемся в деталях языка. Как Java, так и C ++ позволяют изменять доступ к функциям при переоценке. Так называемая «доступность» состоит в том, чтобы использовать символы управления доступом, такие как публичные, защищенные и частные, чтобы изменить ее, чтобы контролировать, можно ли получить доступ к функции. Обычно порядок доступности заключается (поскольку в C ++ нет концепции пакетов, контроль доступа к пакетам не рассматривается в настоящее время, что не влияет на обсуждение здесь):
public> защищен> частные
Возьмите Java в качестве примера:
класс база {защищенный void sayshello () {System.out.println ("Привет в базе"); }} класс Child Extens Base {public void sayshello () {System.out.println ("Привет в ребенке"); }} ПРИМЕЧАНИЕ: функция sayHello() здесь. В базе родительского класса эта функция изменяется с использованием защищенного символа управления доступом. И подклассы используют публику, вместо этого не будет проблем. Когда подклассы переопределяют функции родительского класса, расширение доступности обычно не является проблемой.
Java и C ++ принимают разные стратегии, когда подклассы уменьшают переоборудование доступности в функции родительского класса.
Во -первых, возьмите Java в качестве примера и посмотрите на следующий код:
класс база {public void sayshello () {System.out.println ("Привет в базе"); }} класс Child Extens Base {private void sayshello () {System.out.println ("Привет в ребенке"); }}В приведенном выше коде будет возникнута ошибка компиляции в выделенной строке 8 - этот код не может быть составлен вообще! Java не позволяет подклассам снижать доступность при перезаписи функций родительского класса. Что касается причин, мы можем использовать пример для иллюстрации. Например, мы пишем следующий код за пределами класса:
Базовая база = new Base (); base.sayhello (); base = new Child (); base.sayhello ();
Если предыдущий код может быть скомпилирован, есть вероятность того, что когда базовые точки на новый Base () SayHello () можно получить, но когда базовые указы на новый ребенок () SayHello () не может быть доступен! По мнению Java, это противоречие, и этой проблемы следует избегать. Поэтому Java предусматривает с точки зрения компилятора, что мы не можем написать вышеуказанный код.
Для C ++ ситуация отличается. Давайте посмотрим на пример C ++:
класс база {public: virtual void sayshello () {std :: cout << "Привет в базе"; }} класс ребенок: public base {private: void sayshello () {std :: cout << "Привет в ребенке"; }}Этот код полностью верен в C ++. Обратите внимание, что подкласс здесь снижает доступность при перезаписи функций родительского класса. Если вы не видите никакой проблемы, то мы можем написать следующий код за пределами класса:
Ребенок; Child.sayhello (); // не может быть скомпилирован, потому что SayShello () - это static_cast <base &> (ребенок) .sayhello (); // не может быть составлен, потому что Sayshello ()
Вызов строки 2 терпит неудачу, потому что у ребенка sayHello() является частным и не может быть вызван внешним. Однако, когда мы бросаем ребенка на базовый объект, используя static_cast, все меняется - для базы, sayHello() является общедоступным, поэтому его можно назвать нормально.
С этой целью можно найти следующий пример в разделе «Доступ к виртуальным функциям» главы управления доступом к стандартным членам C ++:
Класс B {public: virtual int f ();}; класс D: public b {private: int f ();}; void f () {d d; B* pb = & d; D* pd = & d; pb-> f (); // ok: b :: f () публично, d :: f () вызывается pd-> f (); // Ошибка: D :: f () является частным}В связи с этим стандарт C ++ дает объяснение:
Доступ проверяется в точке вызова, используя тип выражения, используемого для обозначения объекта, для которого вызывается функция элемента (B* в примере выше). Доступ к функции элемента в классе, в котором она была определена (D в примере выше), в целом не известен.
Есть два ключевых момента для простого перевода:
Из -за этого вызывающие абоненты C ++, кажется, могут «умело» вызовать функции, которые изначально были недоступны благодаря некоторым умелым преобразованию. Более практическим примером является: В QT функция QObject::event() является общедоступной, а ее функция подкласса Qwidget event() изменяется на защиту. Для получения подробной информации вы можете прочитать соответствующий код QT.
Таким образом, когда подклассы переопределяют родительские функции, Java строго ограничивает, что подклассы не могут сузить доступность функции, но C ++ не имеет этого ограничения. Лично я считаю, что с точки зрения разработки программного обеспечения, правила Java, несомненно, имеют более инженерное значение, а вызовы функций более последовательны. Стандарт C ++ значительно упростит реализацию компилятора, но это не является хорошей ссылкой для технического.
PS: Официальная версия стандарта C ++ требует покупки, но проект можно загрузить бесплатно. Адрес скачивания стандартного проекта C ++ можно найти на следующей странице: https://isocpp.org/std/the-standard
Суммировать
Вышеуказанное - все содержание этой статьи. Я надеюсь, что содержание этой статьи имеет определенную справочную ценность для каждого обучения или работы. Если у вас есть какие -либо вопросы, вы можете оставить сообщение для общения. Спасибо за поддержку Wulin.com.