Когда я должен использовать C++ частное наследование?

использовать Mixins для ES6 multiple Inheritance.

let classTwo = Base => class extends Base{
    // ClassTwo Code
};

class Example extends classTwo(ClassOne) {
    constructor() {
    }
}
112
задан 18 March 2009 в 07:18
поделиться

9 ответов

Отметьте после принятия ответа: Это не полный ответ. Прочитайте другие ответы как здесь (концептуально) и здесь (и теоретический и practic), если Вы интересуетесь вопросом. Это - просто необычный прием, который может быть достигнут с частным наследованием. В то время как это воображение , это не ответ на вопрос.

Помимо основного использования просто частного наследования, показанного в FAQ C++ (связанный в комментариях других), можно использовать комбинацию частного и виртуального наследования к изоляция класс (в терминологии.NET) или сделать финал класса (в терминологии Java). Это не общее использование, но так или иначе я нашел это интересным:

class ClassSealer {
private:
   friend class Sealed;
   ClassSealer() {}
};
class Sealed : private virtual ClassSealer
{ 
   // ...
};
class FailsToDerive : public Sealed
{
   // Cannot be instantiated
};

Изолированный может быть инстанцирован. Это происходит от [1 111] ClassSealer и может назвать частного конструктора непосредственно, поскольку это - друг.

FailsToDerive не скомпилирует, как он должен звонить конструктор ClassSealer непосредственно (виртуальное требование наследования), но он не может, поскольку это является частным в Изолированный класс и в этом случае , FailsToDerive не является другом [1 116] ClassSealer.

<час>

РЕДАКТИРОВАНИЕ

Это было упомянуто в комментариях, что это не могло быть сделано универсальным в то время использование CRTP. C++ 11 стандартов удаляет то ограничение путем обеспечения другого синтаксиса для оказания поддержки аргументам шаблона:

template <typename T>
class Seal {
   friend T;          // not: friend class T!!!
   Seal() {}
};
class Sealed : private virtual Seal<Sealed> // ...

, Конечно, это все спорно, так как C++ 11 обеспечивает final контекстное ключевое слово для точно этой цели:

class Sealed final // ...
54
ответ дан Community 5 November 2019 в 09:35
поделиться

Каноническое использование частного наследования "реализовано с точки зрения" отношений (благодаря 'Эффективному C++ Scott Meyers' для этой формулировки). Другими словами, внешний интерфейс наследующего класса не имеет никаких (видимых) отношений к наследованному классу, но он использует его внутренне для реализации его функциональности.

29
ответ дан Harper Shelby 5 November 2019 в 09:35
поделиться

Я думаю критический раздел от , FAQ C++, Облегченный :

А законное, долгосрочное использование для частного наследования состоит в том, когда Вы хотите создать класс Fred, который использует код в классе Wilma и код от класса, Wilma должна вызвать функции членства от Вашего нового класса, Fred. В этом случае Fred называет non-virtuals в Wilma и вызовы Wilma (обычно чистый virtuals) сам по себе, которые переопределяются Fred. Это намного тяжелее относилось бы к составу.

, Если в сомнении, необходимо предпочесть состав по частному наследованию.

18
ответ дан Bill the Lizard 5 November 2019 в 09:35
поделиться

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

, Но Вы правы, это не имеет многих примеров от реального мира.

1
ответ дан gedamial 5 November 2019 в 09:35
поделиться

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

[отредактированный в примере]

Берут пример связанный с вышеупомянутым. Высказывание, что

[...] класс Wilma должна вызвать функции членства от нового класса, Fred.

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

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

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

[отредактированный в другом примере]

Эта страница кратко обсуждает закрытые интерфейсы (от еще одного угла).

4
ответ дан bias 5 November 2019 в 09:35
поделиться

Я использую все это время. Несколько примеров первое, что пришло на ум:

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

Типичный пример происходит конфиденциально из контейнера STL:

class MyVector : private vector<int>
{
public:
    // Using declarations expose the few functions my clients need 
    // without a load of forwarding functions. 
    using vector<int>::push_back;
    // etc...  
};
  • Когда реализация Шаблона "адаптер", наследование конфиденциально от Адаптированного класса сохраняют необходимость передать вложенному экземпляру.
  • Реализовать закрытый интерфейс. Это часто подходит с Шаблоном The Observer. Обычно мой класс Наблюдателя, MyClass заявляют, подписывает себя с некоторым Предметом. Затем только MyClass должен сделать MyClass-> преобразование Наблюдателя. Остальная часть системы не должна знать об этом, таким образом, частное наследование обозначается.
134
ответ дан Serve Laurijssen 24 November 2019 в 02:48
поделиться

Одно полезное использование частного наследования состоит в том, когда у Вас есть класс, который реализует интерфейс, который затем регистрируется в некотором другом объекте. Вы делаете тот интерфейс частным так, чтобы сам класс зарегистрировался и только конкретный объект, что его зарегистрированное в может использовать те функции.

Например:

class FooInterface
{
public:
    virtual void DoSomething() = 0;
};

class FooUser
{
public:
    bool RegisterFooInterface(FooInterface* aInterface);
};

class FooImplementer : private FooInterface
{
public:
    explicit FooImplementer(FooUser& aUser)
    {
        aUser.RegisterFooInterface(this);
    }
private:
    virtual void DoSomething() { ... }
};

Поэтому класс FooUser может назвать закрытые методы FooImplementer через интерфейс FooInterface, в то время как другие внешние классы не могут. Это - большой шаблон для обработки определенных обратных вызовов, которые определяются как интерфейсы.

22
ответ дан Daemin 24 November 2019 в 02:48
поделиться

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

class BigClass;

struct SomeCollection
{
    iterator begin();
    iterator end();
};

class BigClass : private SomeCollection
{
    friend struct SomeCollection;
    SomeCollection &GetThings() { return *this; }
};

Затем, если SomeCollection должен получить доступ к BigClass, он может static_cast<BigClass *>(this). Никакая потребность иметь дополнительное место занимающего элемента данных.

2
ответ дан 24 November 2019 в 02:48
поделиться

Просто, потому что C++ имеет функцию, не означает, что это полезно или что это должно использоваться.

Я сказал бы, что Вы не должны использовать его вообще.

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

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

-1
ответ дан hasen 24 November 2019 в 02:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: