Я не понимаю, какие могут быть проблемы, если конструктор был унаследован от базового класса. Cpp Primer Plus говорит,
Конструкторы отличаются от других методов класса тем, что они создают новые объекты, тогда как другие методы вызываются существующими объектами . Это одна из причин, почему конструкторы не наследуются . Наследование означает, что производный объект может использовать метод базового класса, но, в случае конструкторов, объект не существует до тех пор, пока конструктор не выполнит свою работу.
Я понимаю, что конструктор вызывается до завершения строительства объекта.
Как это может привести к проблемам, если дочерний класс наследует (под наследованием я подразумеваю, что дочерний класс может переопределять метод родительского класса и т. Д. Не просто получая доступ к методу родительского класса ) родительский конструктор?
Я понимаю, что нет необходимости явно вызывать конструктор из кода [не то, что я знаю пока.] Кроме как при создании объектов. Даже тогда вы можете сделать это, используя некоторый механизм для вызова родительского конструктора [В cpp, using ::
или using member initialiser list
, В java using super
]. В Java есть обязательство вызывать его в 1-й строке, я понимаю, что сначала нужно создать родительский объект, а затем продолжить конструирование дочернего объекта.
Это может переопределить это. Но я не могу придумать ситуации, когда это может создать проблему. Если ребенок наследует родительский конструктор, что может пойти не так?
Так что это просто, чтобы избежать наследования ненужных функций. Или есть что-то еще?
источник
Ответы:
В C ++ не может быть надлежащего наследования конструкторов, потому что конструктор производного класса должен выполнять дополнительные действия, которые конструктор базового класса не должен делать и о которых он не знает. Эти дополнительные действия являются инициализацией членов данных производного класса (и в типичной реализации также установка vpointer для ссылки на производные классы vtable).
Когда класс создается, всегда нужно выполнить ряд действий: необходимо вызывать конструкторы базового класса (если есть) и прямые члены, а если есть какие-либо виртуальные функции, vpointer должен быть установлен правильно , Если вы не предоставляете конструктор для класса, то компилятор будет создавать тот , который выполняет необходимые действия , и ничего другого. Если вы делаете предоставить конструктор, но пропустить некоторые из необходимых действий (например, инициализация некоторых членов), то компилятор автоматически добавит недостающие действия в конструктор. Таким образом, компилятор гарантирует, что у каждого класса есть хотя бы один конструктор и что каждый конструктор полностью инициализирует объекты, которые он создает.
В C ++ 11 была введена форма «наследования конструктора», где вы можете дать указание компилятору сгенерировать для вас набор конструкторов, которые принимают те же аргументы, что и конструкторы из базового класса, и просто передают эти аргументы в Базовый класс.
Хотя это официально называется наследованием, на самом деле это не так, потому что есть функция, специфичная для производного класса. Теперь он просто генерируется компилятором, а не явно написан вами.
Эта функция работает так:
Derived
теперь имеет два конструктора (не считая конструкторов копирования / перемещения). Тот, который принимает int и строку, и тот, который принимает только int.источник
m()
и как он будет меняться, если, например, его типint
.using Base::Base
косвенно? Это имело бы большие последствия, если бы я забыл эту строку в производном классе, и мне нужно наследовать конструктор во всех производных классахНепонятно, что вы подразумеваете под «наследованием родительского конструктора». Вы используете слово переопределение , которое предполагает, что вы можете подумать о конструкторах, которые ведут себя как полиморфные виртуальные функции . Я намеренно не использую термин «виртуальные конструкторы», потому что это общее имя для шаблона кода, когда вам фактически требуется уже существующий экземпляр объекта для создания другого.
Полиморфные конструкторы мало полезны вне шаблона «виртуального конструктора», и трудно придумать конкретный сценарий, в котором может быть использован реальный полиморфный конструктор. Очень надуманный пример, который никоим образом не является даже удаленно верным C ++ :
В этом случае вызываемый конструктор зависит от конкретного типа создаваемой или присваиваемой переменной. Его сложно обнаружить во время синтаксического анализа / генерации кода и не имеет никакой полезности: вы знаете конкретный тип, который вы создаете, и вы написали специальный конструктор для производного класса. Следующий действительный код C ++ делает то же самое, немного короче и более явно в том, что он делает:
Вторая интерпретация или, возможно, дополнительный вопрос - что, если конструкторы базового класса автоматически присутствуют во всех производных классах, если они явно не скрыты.
Вам придется написать дополнительный код, чтобы скрыть родительский конструктор, который нельзя использовать при создании производного класса. Это может произойти, когда производный класс специализирует базовый класс таким образом, что определенные параметры становятся неактуальными.
Типичным примером являются прямоугольники и квадраты (обратите внимание, что квадраты и прямоугольники, как правило, не являются заменяемыми по Лискову, поэтому это не очень хороший дизайн, но он подчеркивает проблему).
Если бы Square унаследовал конструктор Rectangle с двумя значениями, вы могли бы создавать квадраты с разной высотой и шириной ... Это логически неправильно, поэтому вы захотите скрыть этот конструктор.
источник
Почему конструкторы не наследуются: ответ на удивление прост: конструктор базового класса «строит» базовый класс, а конструктор унаследованного класса «строит» унаследованный класс. Если унаследованный класс унаследует конструктор, конструктор попытается создать объект базового класса типа, и вы не сможете «построить» объект наследуемого типа.
Какой вид поражает цель закрепления класса.
источник
Самая очевидная проблема с разрешением производному классу переопределять конструктор базового класса состоит в том, что разработчик производного класса теперь отвечает за знание того, как конструировать его базовый класс (ы). Что происходит, когда производный класс не создает базовый класс должным образом?
Кроме того, принцип Liskov-Substitution больше не будет применяться, поскольку вы больше не можете рассчитывать на то, что ваша коллекция объектов базового класса будет совместима друг с другом, потому что нет гарантии, что базовый класс был построен правильно или совместим с другими производными типами.
Еще сложнее, когда добавляется более 1 уровня наследования. Теперь вашему производному классу нужно знать, как создать все базовые классы в цепочке.
Что произойдет, если вы добавите новый базовый класс в начало иерархии наследования? Вы должны обновить все конструкторы производных классов.
источник
Конструкторы принципиально отличаются от других методов:
Так почему они не унаследованы? Простой ответ: потому что всегда есть переопределение, сгенерированное или написанное вручную.
Почему каждому классу нужен конструктор? Это сложный вопрос, и я считаю, что ответ зависит от компилятора. Существует такая вещь, как «тривиальный» конструктор, для которого компилятор не предписывает, что он будет вызван, кажется. Я думаю, что это самое близкое к тому, что вы подразумеваете под наследованием, но по трем причинам, указанным выше, я думаю, что сравнение конструкторов с обычными методами не очень полезно. :)
источник
Каждому классу нужен конструктор, даже по умолчанию.
C ++ создаст для вас конструкторы по умолчанию, кроме случаев, когда вы создаете специализированный конструктор.
В случае, если ваш базовый класс использует специализированный конструктор, вам нужно написать специализированный конструктор в производном классе, даже если оба они одинаковы, и объединить их в цепочку.
C ++ 11 позволяет избежать дублирования кода на конструкторах, используя :
Набор наследующих конструкторов состоит из
Все унаследованные конструкторы, которые не являются конструктором по умолчанию или конструктором копирования / перемещения и подписи которых не соответствуют пользовательским конструкторам в производном классе, неявно объявляются в производном классе. Параметры по умолчанию не наследуются
источник
Вы можете использовать:
Вы спрашиваете, почему вы должны это сделать?
Подкласс может иметь дополнительные свойства, которые, возможно, потребуется инициализировать в конструкторе, или он может инициализировать переменные базового класса другим способом.
Как еще вы могли бы создать объект подтипа?
источник