Всегда ли частное наследство означает «HAS-A»? - PullRequest
0 голосов
/ 04 июня 2018

По словам моего любимого автора, Мистер Скотт Мейерс , наследование и композиция private означает то же самое, что и отношения Has-A.Таким образом, все, что может быть получено из композиции (сдерживание, когда класс A имеет класс B в качестве члена), может быть получено посредством частного наследования и наоборот.

Таким образом, следующий код должен быть отношением Has-A, но, с моей точки зрения, это не так!

class A : private boost::noncopyable {.. this is irrelevant };

Может кто-нибудь сказать, что я пропал?Или как этот код может быть реализован через композицию?

Ответы [ 4 ]

0 голосов
/ 04 июня 2018

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

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

0 голосов
/ 04 июня 2018

boost::noncopyable не имеет реального семантического значения, это просто деталь реализации, запрещающая внукам.

class A : private boost::noncopyable {};

A не имеет boost::noncopyable,поскольку boost::noncopyable пусто, как в прямом, так и в смысле.Здесь вы могли бы сказать, что «A не может быть скопировано», но я в целом согласен с точкой зрения Мейерса в общем случае.

0 голосов
/ 04 июня 2018

Ваш пример все еще является отношением HAS-A.

В качестве примера приведен следующий класс, который примерно эквивалентен boost:noncopyable:

class X {
private:
    X(const X &);
    X &operator=(const X &);
public:
    X() {}
};

Следующие два класса имеютта же функциональность:

class A : private X {
public:
    int a;
    char b;
};

class B {
public:
    int a;
    char b;
    X x;
};

В этом примере A конфиденциально наследуется от X, тогда как B содержит экземпляр X.A нельзя скопировать, потому что он не может вызвать конструктор копирования родителя, а B нельзя скопировать, потому что он не может вызвать конструктор копирования одного из его членов.

A a1;
A a2(a1);   // error
B b1;
B b2(b1);   // error
0 голосов
/ 04 июня 2018

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

class A {
private:
    class B {
        B(const B&) = delete;
        B& operator=(const B&) = delete;
    } b;
};

A не может быть скопировано, потому что его член b не является копируемым.

...