Эффективный C++: препятствует защищенному наследованию?

Я читал " Эффективный C++" Скотта Мейерса (третье издание), и в параграфе в пункте 32: Убедитесь, что публичное наследование "is-a" на странице 151, он делает комментарий (который я выделил жирным шрифтом):

Это верно только для общественного наследства. C++ будет вести себя так, как я описал, только если ученик публично получен из Person. Частное наследование означает нечто совершенно иное (см. Пункт 39), а защищенное наследование - это то, чье значение ускользает от меня до сих пор.

Вопрос: как мне интерпретировать этот комментарий? Мейерс пытается донести, что защищенное наследие редко считается полезным и его следует избегать?

(Я прочитал вопрос " Разница между частным, общедоступным и защищенным наследованием", а также раздел "Частное и защищенное наследование" в C++ FAQ Lite, в котором объясняется, что означает защищенное наследование, но я не дал достаточного представления о том, когда и почему оно было бы полезно.)

5 ответов

Решение

Некоторые сценарии, где вы хотели бы защитить:

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

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

Благодаря множественному наследованию вы можете поиграть с типом наследования базовых классов и создать более разнообразный класс с существующей логикой и реализацией.

Более конкретный пример:

Вы можете создать несколько абстрактных классов, которые следуют логике Design Pattern, скажем, у вас есть:

Observer
Subject
Factory

Теперь вы хотите, чтобы все это было общедоступным, потому что в целом вы можете использовать шаблон для чего угодно.

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

Другой пример:

Допустим, например, что вы хотите наследовать от библиотечного класса (не то чтобы я это поощрял). Допустим, вы хотите сделать свое собственное крутое продолжение std::list<> или "лучше" shared_ptr,

Вы можете получить защиту от базового класса (который предназначен для открытых методов).
Это даст вам возможность использовать ваши собственные пользовательские методы, использовать логику класса и передавать логику в любой производный класс.

Возможно, вы могли бы использовать вместо этого инкапсуляцию, но наследование следует правильной логике IS A (или в этом случае IS своего рода A)

Он не совсем обескураживает защищенное наследство, он просто говорит, что не нашел в этом ничего хорошего. Я никого не видел нигде.

Если вам случится найти несколько действительно полезных вариантов использования, у вас может быть материал для написания книги.:-)

Да, не так много вариантов использования для защищенного или частного наследования. Если вы когда-нибудь задумывались о частном наследовании, скорее всего, состав лучше подходит для вас. (Наследование означает "есть-а", а композиция означает "имеет-а".)

Я предполагаю, что комитет C++ просто добавил это, потому что это было очень легко сделать, и они решили: "Черт, может быть, кто-то найдет хорошее применение для этого". Это не плохая функция, она не приносит никакого вреда, просто никто еще не нашел для нее реального применения.:П

И да и нет. Я сам считаю, что защищенное наследование тоже плохая особенность. Он в основном импортирует всех открытых и защищенных членов базового класса как защищенных.

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

Я думаю, что Скотт Мейер пытается сказать, что вы все еще можете использовать защищенное наследование, если оно решает проблему, но обязательно используйте комментарии для описания наследования, потому что это не семантически ясно.

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

Если ваши коллеги не знают С ++ лучше, чем он, вам, вероятно, следует также избегать защищенного наследования. Все поймут альтернативу, то есть использование композиции.

Однако я могу представить себе случай, когда это может иметь смысл: вам нужен доступ к защищенному члену в классе, код которого вы не можете изменить, но не хотите раскрывать отношения IS-A.

class A {
protected:
  void f(); // <- I want to use this from B!
};

class B : protected A {
private:
  void g() { f(); }
};

Даже в этом случае я бы все же подумал о создании оболочки с открытым наследованием, которая бы открывала защищенные базовые элементы публичными методами, а затем создавал бы эти оболочки.

/*! Careful: exposes A::f, which wasn't meant to be public by its authors */
class AWithF: public A {
public:
  void f() { A::f(); }
};

class B {
private:
  AWithF m_a;
  void g() { m_a.f(); }
};
Другие вопросы по тегам