Re[2]: Почему конструкторы не наследуются?
От: jazzer Россия Skype: enerjazzer
Дата: 25.07.05 15:06
Оценка: +3
Здравствуйте, Oyster, Вы писали:

O> при добавлении нового конструктора в базовом классе он чудесным образом появится во всех наследниках, как в C++.


Ничего подобного в С++ нет.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[6]: Почему конструкторы не наследуются?
От: dshe  
Дата: 25.07.05 15:44
Оценка: -2
Здравствуйте, VladD2, Вы писали:

AS>> Если нужна такая фича, проще перегрузить конструтор, а в нем написать super(). И все, и никаких проблем


VD>Помтоу что это море никому не нужного кода. Вот представь... Создал я реализацию некой коллекции. Причем в рассчете на то, что напрямую ее создавать никто не будет, а на против, будут порождать он нее наследников. Так вот в этой коллекции есть, предположим, 20 конструкторов. Их все прейдется описать в наследнике. Да еще не ошибиться.


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

Одно из предназначений конструктора -- инициализировать поля объекта. Поэтому часто бывает достаточно одного "главного" конструктора (возможно с большим количеством аргументов), который инициализирует все поля. Однако конструктор с большим количеством аргументов использовать неудобно, поэтому и создаются дополнительные конструкторы (с меньшим количеством аргументов), которые некоторые поля инициализируют некими умолчательными значениями. Полагаю, что твой класс для наследования с 20 конструкторами ничего не потеряет если будет иметь всего один "главный" конструктор. А на остальных конструкторах данного класса можно было бы и сэкономить.

Что касается наследников, то на их конструкторах сэкономить, в общем случае, уже не получится, поскольку им в любом случае надо инициализировать свои поля. "Наследование конструкторов" могло бы быть безопасным лишь в том случае, если бы наследник не добавлял своих полей; либо явно указывал, что свои поля он инициализировать значениями, отличными от умолчательных, не собирается; либо явно переопределял все "унаследованные" конструкторы.
--
Дмитро
Re[5]: Почему конструкторы не наследуются?
От: dshe  
Дата: 25.07.05 15:57
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, dshe, Вы писали:


D>>Необходимость возникает когда в наследнике добавляется поле, которое должно быть инициализировано (в конструкторе) ненулевым значением. Так называемое "наследование конструкторов" скорее всего приведет к тому, что у класса-наследника будет много конструкторов, унаследованных от предков самой разной близости, которые не инициализируют объект полностью. А это чревато ошибками. На мой взгляд, гораздо проще (и безопаснее) явно объявить конструктор, в котором просто вызвать base, чем скрывать за private или protected лишние конструкторы.


VD>Ну, и почему не поступать так же как с конструкторами без параметров? Ну, наследовать конструкторы если в наследнике они не определены явно.


В смысле, наследовать конструкторы, если в наследнике ни один конструктор не определен явно? Наверняка существуют условия при которых "наследование конструкторов" безопасно. Но в любом случае, "лишние" конструкторы в наследнике не должны быть сюрпризом для программиста.
--
Дмитро
Re[3]: Почему конструкторы не наследуются?
От: Oyster Украина https://github.com/devoyster
Дата: 26.07.05 00:57
Оценка:
Здравствуйте, jazzer, Вы писали:

J>Здравствуйте, Oyster, Вы писали:


O>> при добавлении нового конструктора в базовом классе он чудесным образом появится во всех наследниках, как в C++.


J>Ничего подобного в С++ нет.


Туплю — позабывал уже...
Re[7]: Почему конструкторы не наследуются?
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.07.05 02:44
Оценка: +1
Здравствуйте, dshe, Вы писали:

D>Создавать 20 конструкторов в классе, предназначенном исключительно для наследования от него, с твоей стороны, -- это плыть против течения. Тем более, что ты прекрасно знаешь, что кому-то (может быть и тебе) придется в наследниках их все определять заново.


Это жизнь. Ну, нужны эти 20 конструкторов. Мало ил как объект будет инициализироваться?

D>Одно из предназначений конструктора -- инициализировать поля объекта. Поэтому часто бывает достаточно одного "главного" конструктора (возможно с большим количеством аргументов), который инициализирует все поля.


"Часто", "бывает"... это не те категории. Бывает по разному. Бывает, что нужно унаследовать конструкторы. Ну, не ввел я ни одного нового поля. Так зачем же мне переоеределяь все 20 конструкторов? А ведь с теми самыми базовыми классами коллекций так и бывает.

D> Однако конструктор с большим количеством аргументов использовать неудобно, поэтому и создаются дополнительные конструкторы (с меньшим количеством аргументов), которые некоторые поля инициализируют некими умолчательными значениями. Полагаю, что твой класс для наследования с 20 конструкторами ничего не потеряет если будет иметь всего один "главный" конструктор. А на остальных конструкторах данного класса можно было бы и сэкономить.


Это экономия на пользователях твоего класса. В общем, плохое решение.

D>Что касается наследников, то на их конструкторах сэкономить, в общем случае, уже не получится, поскольку им в любом случае надо инициализировать свои поля.


Предположим, нет полей. Хотя я уже повторяюсь.

D> "Наследование конструкторов" могло бы быть безопасным лишь в том случае, если бы наследник не добавлял своих полей; либо явно указывал, что свои поля он инициализировать значениями, отличными от умолчательных, не собирается; либо явно переопределял все "унаследованные" конструкторы.


Ну, и в чем проблема? Если полей нет или все они инициализируются по месту, то что может помешать наследованию конструктора?

ЗЫ

В общем, это все попытки скрыть явный прощет в дизайне языков.
... << RSDN@Home 1.2.0 alpha rev. 591>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: Почему конструкторы не наследуются?
От: Дарней Россия  
Дата: 26.07.05 03:43
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Какими средствами? Т.е., если инвариантом Derived является то, что Base

ПК>проинициализирован someFlag = true, то как это обеспечить при открытом
ПК>конструкторе Base(bool)?

ПК>Варианты явным образом закрывать конструкторы подходят не вполне, т.к.

ПК>при добавлении базовых классов необходимо будет просматривать всех
ПК>наследников, что в общем случае сделать нереально.

Добавлении базовых классов? Это как?
И зачем просматривать всех наследников? Ничего не пойму
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[9]: Почему конструкторы не наследуются?
От: Павел Кузнецов  
Дата: 26.07.05 06:29
Оценка:
Дарней,

ПК>> Варианты явным образом закрывать конструкторы подходят не вполне, т.к.

ПК>> при добавлении базовых классов необходимо будет просматривать всех
ПК>> наследников, что в общем случае сделать нереально.

Д> Добавлении базовых классов? Это как?


Оговорился. При добавлении конструкторов в базовых классах.

Д> И зачем просматривать всех наследников? Ничего не пойму


Чтобы убедиться, что их инварианты не нарушаются при добавлении нового конструктора в базе.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[3]: Почему конструкторы не наследуются?
От: dshe  
Дата: 26.07.05 07:03
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, AndrewVK, Вы писали:


SC>>>В чём глубокий смысл сабжа в C#?


AVK>>Одна из причин — необходимость убирать базовые конструкторы.


VD>Лучше бы решили проблему скрытия методов в наследнике.


А зачем может понадобиться скрывать методы в наследнике? Если наследник не реализует весь тот интерфейс, который он унаследовал, то он может и не должен быть наследником? поскольку в этом случае явно нарушается LSP.

Кстати, в С++ по-моему можно в наследнике делать методы приватными, которые в базовом были public.
struct A {
    virtual void f() {}
};

class B: public A {
    virtual void f() {}
};

Что приводит к следующему парадоксу, на мой взгляд.
B *b = new B();
b->f(); // так нельзя -- ошибка компиляции
((A *) b)->f(); // а так уже можно

Получается, что вполне легальными средствами можно доступиться к скрытому методу.
--
Дмитро
Re[8]: Почему конструкторы не наследуются?
От: dshe  
Дата: 26.07.05 07:11
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>В общем, это все попытки скрыть явный прощет в дизайне языков.


ок. Укажи все те условия, при которых, как ты считаешь, наследовать конструкторы безопасно.
--
Дмитро
Re[10]: Почему конструкторы не наследуются?
От: Дарней Россия  
Дата: 26.07.05 07:34
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК> Дарней,


ПК>>> Варианты явным образом закрывать конструкторы подходят не вполне, т.к.

ПК>>> при добавлении базовых классов необходимо будет просматривать всех
ПК>>> наследников, что в общем случае сделать нереально.

Д>> Добавлении базовых классов? Это как?


ПК>Оговорился. При добавлении конструкторов в базовых классах.


Д>> И зачем просматривать всех наследников? Ничего не пойму


ПК>Чтобы убедиться, что их инварианты не нарушаются при добавлении нового конструктора в базе.


Не просто нового конструктора в базе. А такого нового конструктора, который требует соблюдения неких инвариантов его вызова во всех наследниках. Это — во первых.
А во вторых — в этом случае достаточно сделать наследника от базового класса, который перекрывает этот конструктор и делает его protected, а для наследников оставляет открытый конструктор с соблюдением инварианта. Все порожденные классы наследуешь уже от него. И всё!
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[4]: Почему конструкторы не наследуются?
От: Дарней Россия  
Дата: 26.07.05 07:40
Оценка: :)
Здравствуйте, dshe, Вы писали:

D>А зачем может понадобиться скрывать методы в наследнике? Если наследник не реализует весь тот интерфейс, который он унаследовал, то он может и не должен быть наследником? поскольку в этом случае явно нарушается LSP.


Чтобы не приходилось писать в документации вот так:

Array.IList.Add Method
Implements IList.Add. Always throws NotSupportedException.


D>Что приводит к следующему парадоксу, на мой взгляд.

D>
D>B *b = new B();
b->>f(); // так нельзя -- ошибка компиляции
D>((A *) b)->f(); // а так уже можно
D>

D>Получается, что вполне легальными средствами можно доступиться к скрытому методу.

А что здесь парадоксального? Программист просто дает понять, что хотя метод и можно вызвать, но лучше этого не делать.
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[11]: Почему конструкторы не наследуются?
От: dshe  
Дата: 26.07.05 07:45
Оценка:
Здравствуйте, Дарней, Вы писали:

ПК>>Чтобы убедиться, что их инварианты не нарушаются при добавлении нового конструктора в базе.


Д>Не просто нового конструктора в базе. А такого нового конструктора, который требует соблюдения неких инвариантов его вызова во всех наследниках. Это — во первых.


Как новый конструктор в базовом классе обеспечит инициализацию всех полей в тех наследниках, которые их, все-таки, несмотря ни на что, добавляют?

Д>А во вторых — в этом случае достаточно сделать наследника от базового класса, который перекрывает этот конструктор и делает его protected, а для наследников оставляет открытый конструктор с соблюдением инварианта. Все порожденные классы наследуешь уже от него. И всё!


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

Кстати, эти манипуляции с промежуточным базовым классом -- разве это не похоже на написание массы ненужного кода?
--
Дмитро
Re[9]: Почему конструкторы не наследуются?
От: Дарней Россия  
Дата: 26.07.05 07:50
Оценка:
Здравствуйте, dshe, Вы писали:

D>ок. Укажи все те условия, при которых, как ты считаешь, наследовать конструкторы безопасно.


Это безопасно всегда, когда наследники не накладывают ограничений на параметры вызова открытых конструкторов базы. Этого достаточно?
Впрочем, в данном случае это тоже безопасно Просто требует дополнительных действий в виде создания дополнительного класса в иерархии.
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[12]: Почему конструкторы не наследуются?
От: Дарней Россия  
Дата: 26.07.05 08:03
Оценка:
Здравствуйте, dshe, Вы писали:

D>Как новый конструктор в базовом классе обеспечит инициализацию всех полей в тех наследниках, которые их, все-таки, несмотря ни на что, добавляют?


Программисты, которые не ищут себе лишних проблем на задницу, делают это вот так:
class MyClass : BaseClass
{
  SomeClass someVar = new SomeClass();
}

Какие проблемы ты здесь видишь?

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


Мне кажется, ты просто не понял, о чем идет речь.

D>Кстати, эти манипуляции с промежуточным базовым классом -- разве это не похоже на написание массы ненужного кода?


Немного похоже. Разница только в том, что в одном случае мы делаем один вспомогательный класс и наследуемся от него, а вдругом — копипейстим код вызова конструктора в десятки классов-наследников.
Для тебя это не имеет значения?
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[5]: Почему конструкторы не наследуются?
От: dshe  
Дата: 26.07.05 08:06
Оценка: :)
Здравствуйте, Дарней, Вы писали:

Д>Здравствуйте, dshe, Вы писали:


D>>А зачем может понадобиться скрывать методы в наследнике? Если наследник не реализует весь тот интерфейс, который он унаследовал, то он может и не должен быть наследником? поскольку в этом случае явно нарушается LSP.


Д>Чтобы не приходилось писать в документации вот так:

Д>

Д>Array.IList.Add Method
Д>Implements IList.Add. Always throws NotSupportedException.


D>>Что приводит к следующему парадоксу, на мой взгляд.

D>>
D>>B *b = new B();
b->>>f(); // так нельзя -- ошибка компиляции
D>>((A *) b)->f(); // а так уже можно
D>>

D>>Получается, что вполне легальными средствами можно доступиться к скрытому методу.

Д>А что здесь парадоксального? Программист просто дает понять, что хотя метод и можно вызвать, но лучше этого не делать.


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

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

По поводу Array.IList.Add Method: то, что метод всегда выбрасывает исключение -- не образец для подражания.
--
Дмитро
Re[6]: Почему конструкторы не наследуются?
От: Дарней Россия  
Дата: 26.07.05 08:15
Оценка: 1 (1)
Здравствуйте, dshe, Вы писали:

D>А чем тогда NotSupportedException не подошел? Тоже способ дать понять, что хотя метод и можно вызвать, но лучше этого не делать.


Тем, что он не срабатывает во время компиляции.

D>в принципе использоваться не могут.


С помощью отражения, unsafe и/или иных трюков можно использовать любые скрытые методы и поля, если у программиста возникнет такое желание.
Поэтому отложим вакуумных сфероконей в сторону и поговорим о более приземленных вещах. Например, защите от нечаянной ощибки. Сокрытие методов эту задачу решает — этого вполне достаточно.

D>По поводу Array.IList.Add Method: то, что метод всегда выбрасывает исключение -- не образец для подражания.


В данном случае это скорее кривой дизайн. Тем не менее, такая необходимость бывает, и нередко. Сейчас ее можно решить только инкапсуляцией и копи-пейстом гор кода, что не есть хорошо — и к тому же, все равно не дает никаких гарантий.
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[13]: Почему конструкторы не наследуются?
От: dshe  
Дата: 26.07.05 08:26
Оценка: +1
Здравствуйте, Дарней, Вы писали:

Д>Здравствуйте, dshe, Вы писали:


D>>Как новый конструктор в базовом классе обеспечит инициализацию всех полей в тех наследниках, которые их, все-таки, несмотря ни на что, добавляют?


Д>Программисты, которые не ищут себе лишних проблем на задницу, делают это вот так:


calm down. различия во взглядах -- это не повод делать замечания, которые могут восприниматься как оскорбление.

Д>Программисты, которые не ищут себе лишних проблем на задницу, делают это вот так:

Д>
Д>class MyClass : BaseClass
Д>{
Д>  SomeClass someVar = new SomeClass();
Д>}
Д>

Д>Какие проблемы ты здесь видишь?

Для поля someVar (в данном примере), возможно не существует умолчательного значения, типа new SomeClass(). И во всех конструкторах (своих) оно инициализируется через параметр. Предсказать, какие конструкторы будут добавлены в базовый класс, для того, чтобы их скрыть заранее, либо должным образом переопределить -- задача нереальная.

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


Д>Мне кажется, ты просто не понял, о чем идет речь.


Возможно. Объясни тогда другими словами. Я пытаюсь принять вашу позицию и найти в ней уязвимые места.
--
Дмитро
Re[14]: Почему конструкторы не наследуются?
От: Дарней Россия  
Дата: 26.07.05 08:43
Оценка:
Здравствуйте, dshe, Вы писали:

D>Для поля someVar (в данном примере), возможно не существует умолчательного значения, типа new SomeClass(). И во всех конструкторах (своих) оно инициализируется через параметр.


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

D>Предсказать, какие конструкторы будут добавлены в базовый класс, для того, чтобы их скрыть заранее, либо должным образом переопределить -- задача нереальная.


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

D>Возможно. Объясни тогда другими словами. Я пытаюсь принять вашу позицию и найти в ней уязвимые места.


А чего тут непонятного? Промежуточный класс гарантирует соблюдение инвариантадля всей подветки своих наследников. Достигается это тем, что конструктор промежуточного класса соблюдает инвариант всегда, а наследники могут вызвать только этот конструктор, но не конструктор базового класса напрямую.
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[15]: Почему конструкторы не наследуются?
От: dshe  
Дата: 26.07.05 09:01
Оценка:
Здравствуйте, Дарней, Вы писали:

Д>Здравствуйте, dshe, Вы писали:


D>>Для поля someVar (в данном примере), возможно не существует умолчательного значения, типа new SomeClass(). И во всех конструкторах (своих) оно инициализируется через параметр.


Д>В таком случае, тебе все равно придется создавать конструкторы вручную — неважно, есть наследование конструкторов или нет


Верно. Только в случае если конструкторы не наследуются по умолчанию, я буду уверен, что никто не просочится без моего ведома.
--
Дмитро
Re[16]: Почему конструкторы не наследуются?
От: Дарней Россия  
Дата: 26.07.05 09:08
Оценка:
Здравствуйте, dshe, Вы писали:

D>Верно. Только в случае если конструкторы не наследуются по умолчанию, я буду уверен, что никто не просочится без моего ведома.


А если будут, ты все равно получишь ворнинг, что поле не проинициализировано
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.