Подтвердить что ты не робот

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

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

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

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

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

4b9b3361

Ответ 1

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

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

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

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

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

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

Observer
Subject
Factory

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

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

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

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

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

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

Ответ 2

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

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

Ответ 3

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

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

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

Ответ 4

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

Я предполагаю, что комитет С++ просто добавил это, потому что это было очень легко сделать, и они подумали: "черт возьми, может быть, кто-то найдет для этого хорошее применение". Это не плохая особенность, это не наносит вреда, просто никто не нашел для нее реального использования.: P

Ответ 5

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

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

Я могу представить себе случай, когда это может иметь смысл: вам нужен доступ к защищенному члену в классе, код которого вы не можете изменить, но вы не хотите раскрывать отношения 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(); }
};