Почему C ++ запрещает частное наследование конечного класса? - PullRequest
0 голосов
/ 25 декабря 2018

C ++ 11 ввел ключевое слово final в C ++.

Его можно использовать в виртуальном методе или в классе .

Объявление класса final запрещает любое наследование : публичное, защищенное и частное.

struct A final {
};

class B: private A {
};

 error: base 'A' ^ is marked 'final'

Хотя разумно запретить публичное наследование (например, если в моем классе нет виртуального деструктора или по другим причинам), почему я должен запретить частное наследование?

Может быть, если final запретить только публичное наследование ,что std::string и другие его друзья в std были бы final - , как они должны - , из-за отсутствия виртуального деструктора?

РЕДАКТИРОВАТЬ:

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

Ответы [ 2 ]

0 голосов
/ 25 декабря 2018

В дополнение к сказанному Story Teller, рассмотрим причину для введения final: она должна помочь оптимизации.

Когда класс final, и у вас естьПо указанию, компилятор может доказать , какую функцию-член вы вызываете, даже если это virtual.Если класс не является final, указатель может фактически быть указателем на некоторый производный класс, который может переопределить метод virtual, вызывая полный динамический поиск в vtable.

Независимо от того, является ли наследование private или нет, всегда можно создать указатель базового класса.В случае наследования private создание этого указателя базового класса будет ограничено производным классом, производным классом и любой базой производного класса, который все еще содержит больше кода, чем у оптимизатора для его создания.решения.Таким образом, только запрещение all наследования позволяет выполнять оптимизацию виртуального вызова.

0 голосов
/ 25 декабря 2018

Наследование есть наследование.Доступность к нему ортогональна.Он защищает только от статически обработки производного класса в качестве базового за пределами области действия производного класса.Это не имеет значения во время выполнения, и если частное наследование было разрешено, вы могли бы написать следующее:

struct C {
    virtual void foo() {}
};

struct A final : C {
    virtual void foo() {}
};

void baz(A& ref) { ref.foo(); }

class B: private A {
   virtual void foo() {}
   void bar() {
       baz(*this);
   }
};

Частное наследование не мешает вам использовать полиморфизм во время выполнения.Если final предназначено для полного предотвращения дальнейшего переопределения, то частное наследование должно быть включено в запрет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...