Эффективный C++: препятствует защищенному наследованию?
Я читал " Эффективный C++" Скотта Мейерса (третье издание), и в параграфе в пункте 32: Убедитесь, что публичное наследование "is-a" на странице 151, он делает комментарий (который я выделил жирным шрифтом):
Это верно только для общественного наследства. C++ будет вести себя так, как я описал, только если ученик публично получен из Person. Частное наследование означает нечто совершенно иное (см. Пункт 39), а защищенное наследование - это то, чье значение ускользает от меня до сих пор.
Вопрос: как мне интерпретировать этот комментарий? Мейерс пытается донести, что защищенное наследие редко считается полезным и его следует избегать?
(Я прочитал вопрос " Разница между частным, общедоступным и защищенным наследованием", а также раздел "Частное и защищенное наследование" в C++ FAQ Lite, в котором объясняется, что означает защищенное наследование, но я не дал достаточного представления о том, когда и почему оно было бы полезно.)
5 ответов
Некоторые сценарии, где вы хотели бы защитить:
У вас есть базовый класс с методами, в которых вы знаете, что никогда не хотите раскрывать функциональность снаружи, но знаете, что это будет полезно для любого производного класса.
У вас есть базовый класс с членами, которые должны логически использоваться любым классом, который расширяет этот класс, но никогда не должен быть представлен снаружи.
Благодаря множественному наследованию вы можете поиграть с типом наследования базовых классов и создать более разнообразный класс с существующей логикой и реализацией.
Более конкретный пример:
Вы можете создать несколько абстрактных классов, которые следуют логике 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(); }
};