Эффективный C ++: препятствует защищенному наследованию? - PullRequest
21 голосов
/ 26 июня 2011

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

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

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

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

Ответы [ 5 ]

10 голосов
/ 26 июня 2011

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

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

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

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

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

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

Observer
Subject
Factory

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

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

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

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

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

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

5 голосов
/ 26 июня 2011

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

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

3 голосов
/ 26 июня 2011

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

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

3 голосов
/ 26 июня 2011

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

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

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

2 голосов
/ 27 июня 2011

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

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

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