Re[17]: Почему конструкторы не наследуются?
От: VladD2 Российская Империя www.nemerle.org
Дата: 27.07.05 03:40
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Да, это известный глюк. Но если говорить об изменении языка, то введение strong typedef

ПК>могло бы решить проблему.

ПК>http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1706.pdf


Могло бы... это здорово. Но не в плюсах, ни в Шарпе этого нет.

V>> Ну, и у конкретных типов коллекций могут переопределяться некоторые вируальные методы.


ПК>Вообще-то, в данном случае мне кажтся, что наследникам не понадобятся все конструкторы

ПК>базовых классов, т.к. область использования наследников очень ограничена: создали в конструкторе содержащего класса -- и все дела. На универсальность такая обертка по определению не претендует.
ПК>Так что, имхо, и проблемы в данном случае нет...

Это все "твое имхо", а по жизни коллекции создаются и используются в разных местах по разному. И полноценный набор конструкторов не помешал бы. Описывать же их врнучную для каждого типа коллекций откровено в лом. Вот и плюют на них все.
... << RSDN@Home 1.2.0 alpha rev. 591>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[18]: Почему конструкторы не наследуются?
От: Павел Кузнецов  
Дата: 27.07.05 04:18
Оценка:
VladD2,

V> требуется именно введение нового типа. Ну, и у конкретных типов

V> коллекций могут переопределяться некоторые вируальные методы.

Ну, если уже виртуальные методы переопределяются, то не факт, что конструкторы
от базового класса подойдут... Можно пример?
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[18]: Почему конструкторы не наследуются?
От: Павел Кузнецов  
Дата: 27.07.05 04:33
Оценка:
VladD2,

V> Могло бы... это здорово. Но не в плюсах, ни в Шарпе этого нет.


В плюсах более-менее неплохо имитируется в степени, достаточной для практических
целей, с помощью шаблонов конструкторов:
template< class T, class Tag >
struct strong_typedef : T
{
  strong_typedef( T const& t ) : T(t) { }

  template< class A1 >
  strong_typedef( A1& a1 ) : T(a1) { }

  template< class A1, class A2 >
  strong_typedef( A1& a1, A2& a2 ) : T(a1, a2) { }

  template< class A1, class A2, class A3 >
  strong_typedef( A1& a1, A2& a2, A3& a3 ) : T(a1, a2, a3) { }

  // . . .
};

Использование:
struct my_unique_collection_tag;
typedef strong_typedef< Collection<int>, my_unique_collection_tag > MyUniqueCollection;


Хотя тоже, безусловно, не без недостатков:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1385.htm
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[11]: Почему конструкторы не наследуются?
От: Павел Кузнецов  
Дата: 27.07.05 06:26
Оценка:
Дарней,

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


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

ПК>> конструктора в базе.

Д> Не просто нового конструктора в базе. А такого нового конструктора,

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

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

Д> Это — во первых. А во вторых — в этом случае достаточно сделать наследника

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

Уже поздно. Они все уже унаследованны от самого класса, в который собрались
добавлять новый конструктор. Или же продемонстрируй, пожалуйста, общую практику
добавления подобных промежуточных классов "на всякий случай".
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[3]: Почему конструкторы не наследуются?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 27.07.05 08:29
Оценка: +1
Здравствуйте, VladD2, Вы писали:

VD>Лучше бы решили проблему скрытия методов в наследнике. А то нобходимость скрывать конструкторы возникает не чаще чем обычные методы. В общем, не логично.


ИМХО намного чаще, практически всегда. Просто ты обычно не обращаешь внимания на такие случаи, а вот когда ситуация обратная думаешь что так всегда и бывает. Исключение здесь составляют лишь конструкторы без параметров, но вот как раз для них в C# есть специальная синтаксическая затычка.
... << RSDN@Home 1.2.0 alpha rev. 596>>
AVK Blog
Re[5]: Почему конструкторы не наследуются?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 27.07.05 08:29
Оценка: 1 (1)
Здравствуйте, Дарней, Вы писали:

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

Д>

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


Во-первых этот метод и так скрытый и в публичном интерфейсе массивов отсутствует. Проявляется он только когда явно приводим массив к IList (в котором этот метод присутствует по определению).
Во-вторых это следствие ошибки проектирования интерфейсов коллекций. Если бы вместо IList было два интерфейса — IIndexCollection и IMutableCollection, то проблемы такой не было бы.

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


Явная реализация интерфейсов неплохо с этим справляется.
... << RSDN@Home 1.2.0 alpha rev. 596>>
AVK Blog
Re[7]: Почему конструкторы не наследуются?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 27.07.05 08:40
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Кстати, проблему можно было бы решить так как это сделано в Дельфи. То есть разрешать только повышать уровень видимости. Тогда можно было бы создавать промежуточные классы с, предполжим, protected свойствами и делать их видимыми в наследниках.


Да, так конечно проблем намного меньше. С другой стороны и ситуация такая нужна бывает нечасто (хотя, опять же, вопрос проектирования библиотек).
А вобще, если немножко пофантазировать, то можно отказаться от классического наследования, оставив реализацию интерфейсов (и множественное наследование их между собой) и добавив миксины (как, кстати, правильно по-русски, подмешивания?).
... << RSDN@Home 1.2.0 alpha rev. 596>>
AVK Blog
Re[19]: Почему конструкторы не наследуются?
От: VladD2 Российская Империя www.nemerle.org
Дата: 27.07.05 15:06
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>VladD2,


V>> требуется именно введение нового типа. Ну, и у конкретных типов

V>> коллекций могут переопределяться некоторые вируальные методы.

ПК>Ну, если уже виртуальные методы переопределяются, то не факт, что конструкторы

ПК>от базового класса подойдут... Можно пример?

Скачай R# и в проекте RSharp.Parser.RsModel погляди коллекции из RSharp\RSharp.Parser.RsModel\CodeDom\Collections\Generic\
... << RSDN@Home 1.2.0 alpha rev. 591>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Почему конструкторы не наследуются?
От: Sinclair Россия https://github.com/evilguest/
Дата: 29.07.05 06:24
Оценка: +1
Здравствуйте, VladD2, Вы писали:
VD>А еще лучше позволить вручную скрывать любые методы.
Ну, instance метод не особенно-то скроешь, т.к. он будет доступен через приведение к предку. А вот конструкторы можно было бы и поскрывать.
Тут вопрос ровно в том, что чаще встречается — необходимость открыть конструктор предка или закрыть его.
Потому как для "открытия" и для закрытия потребуется совершенно одинаковый код. Единственное дополнение, которое я бы сделал для данного случая (сахар):
public class BaseClass
{
  public BaseClass(int capacity) 
    {
      ...
    }
}

public class DerivedClass: BaseClass
{
  public DerivedClass(int); 
    // эквивалентно следующему:
  public DerivedClass(int capacity): base(capacity)
    {
    }    
    
}

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

public class BaseClass
{
    [Inherit]
  public BaseClass(int capacity) 
    {
      ...
    }
    [Inherit]
    public BaseClass(IEnumerable source)
    {
    }
}

public class DerivedClass: BaseClass
{
  // подразумеваемые конструкторы, предоставленные компилятором:
//  public DerivedClass(int capacity): base(capacity)
//    {
//    }    
//    public DerivedClass(IEnumerable source): base(capacity)
//    {
//    }
}
public class DerivedClass2: BaseClass
{
  // явное сокрытие конструктора:
  private DerivedClass2(int);
    // частичное сокрытие и снятие атрибута Inherit:
    [Inherit(false)]
    protected DerivedClass2(IEnumerable source);
}
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[8]: Почему конструкторы не наследуются?
От: Sinclair Россия https://github.com/evilguest/
Дата: 29.07.05 06:24
Оценка: 26 (1)
Здравствуйте, AndrewVK, Вы писали:
AVK>Да, так конечно проблем намного меньше. С другой стороны и ситуация такая нужна бывает нечасто (хотя, опять же, вопрос проектирования библиотек).
AVK>А вобще, если немножко пофантазировать, то можно отказаться от классического наследования, оставив реализацию интерфейсов (и множественное наследование их между собой) и добавив миксины (как, кстати, правильно по-русски, подмешивания?).
примеси
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[6]: Почему конструкторы не наследуются?
От: Дарней Россия  
Дата: 11.08.05 10:36
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Явная реализация интерфейсов неплохо с этим справляется.


Вот только есть "один маленький нюанс" — она не работает для методов, унаследованных от базового класса.
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[12]: Почему конструкторы не наследуются?
От: Дарней Россия  
Дата: 11.08.05 10:39
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Для того, чтобы убедиться, что новый конструктор не нарушит инварианты существующих

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

То же самое можно сказать про добавление в базовый класс новых методов. И что, наследование методов тоже надо запретить?

ПК>Уже поздно. Они все уже унаследованны от самого класса, в который собрались

ПК>добавлять новый конструктор. Или же продемонстрируй, пожалуйста, общую практику
ПК>добавления подобных промежуточных классов "на всякий случай".

А вот если они "уже" унаследованы от базового класса, а соблюдение инвариантов во всех наследниках гарантируется только методом copy-paste, то разработчику этой архитектуры нужно прямо сейчас больно бить по голове.
Да и рефакторинг еще никто не отменял.
Всех излечит, исцелит
добрый Ctrl+Alt+Delete
Re[8]: Почему конструкторы не наследуются?
От: vdimas Россия  
Дата: 11.08.05 18:01
Оценка: -1
Здравствуйте, VladD2, Вы писали:


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


То, что эту ситуацию никто не гарантирует. Например:
class Base {
    int i;

    public Base(int i) { this.i = i; }

}

class Derived : Base {
    double readonly d;
    
    public Derived(int i, double d) : base(i) {
        this.d = d;
    }
}


Если бы конструкторы наследовались, то мы получили бы грабли в виде возможности неккоректного создания Derived. Intellisense дает нам подсказку двух конструкторов, бери на здоровье. Лекарство состояло бы в принудительном переопределении базовых конструкторов как private. Тогда бы нарушалась инкапсуляция базового класса, ибо любые незначительные изменения в нем (скажем — ввод нового конструктора) потребовал бы доработки ВСЕХ наследников. И жили бы мы весело
Re[14]: Почему конструкторы не наследуются?
От: vdimas Россия  
Дата: 11.08.05 18:18
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>P.S.


ПК>> Все проще: для предоставления утилит к существующему классу не нужно от

ПК>> него наследоваться. Нужно просто предоставить утилиты. В C++ для этого
ПК>> есть "свободные" функции. В C# можно сделать класс со статическими
ПК>> методами. И не будет никаких проблем со скрытыми конструкторами и т.п.

ПК>А для тех редких случаев, где, действительно, имеет смысл наследоваться

ПК>не изменяя инварианты, затрагиваемые конструкторами, в C++ обсуждается введение
ПК>явной возможности наследовать конструкторы базового класса:
ПК>http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1583.pdf

синтаксис не тот, хотелось бы так:

struct Base {
    int i;
    Base(int i_) : i(i_) {}
};

struct Derived : Base {
    using Base::Base;
};


аналогично синтаксиса using для других мемберов.
Re[9]: Почему конструкторы не наследуются?
От: VladD2 Российская Империя www.nemerle.org
Дата: 11.08.05 18:27
Оценка:
Здравствуйте, vdimas, Вы писали:

Такое ощущение, что ты мои слова не читашь.

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


V>Если бы конструкторы наследовались, то мы получили бы грабли в виде возможности неккоректного создания Derived.


А если все же полей нет, или все инициализируется по месту?

V> Intellisense дает нам подсказку двух конструкторов, бери на здоровье. Лекарство состояло бы в принудительном переопределении базовых конструкторов как private. Тогда бы нарушалась инкапсуляция базового класса, ибо любые незначительные изменения в нем (скажем — ввод нового конструктора) потребовал бы доработки ВСЕХ наследников. И жили бы мы весело


Да вариантов придумать можно много. Плохо что выбран был самый примитивный.
... << RSDN@Home 1.2.0 alpha rev. 591>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[10]: Почему конструкторы не наследуются?
От: vdimas Россия  
Дата: 12.08.05 08:13
Оценка: 2 (2)
Здравствуйте, VladD2, Вы писали:

VD>Такое ощущение, что ты мои слова не читашь.


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


V>>Если бы конструкторы наследовались, то мы получили бы грабли в виде возможности неккоректного создания Derived.


VD>А если все же полей нет, или все инициализируется по месту?


Я хорошо читаю, но не представляю, как это все констроллировать в реальной программе. Слишком опасным было бы наличие такого правила в неявном виде. Необходимо ср-во явного задания ситуации "наследования" кострукторов.

V>> Intellisense дает нам подсказку двух конструкторов, бери на здоровье. Лекарство состояло бы в принудительном переопределении базовых конструкторов как private. Тогда бы нарушалась инкапсуляция базового класса, ибо любые незначительные изменения в нем (скажем — ввод нового конструктора) потребовал бы доработки ВСЕХ наследников. И жили бы мы весело


VD>Да вариантов придумать можно много. Плохо что выбран был самый примитивный.


Да это первое, что приходит в голову. Если подобная опция будет нам дана неявно (не дай бог), мы устанем "закрывать" базовые конструкторы.

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

Так вот, что делать компилятору в этом случае? Оставлять видимыми другие конструкторы вместе с вновь определенными или нет??? Я знаю как минимум одно место, где было бы неплохо оставлять — это наследники типизированных коллекций (и то не всегда).

Я как бы за то, чтобы иметь директиву, например, using в самом классе, но с определенным синтаксисом для конструктора. Что-то типа так:

class DerivedClass : BaseClass {
  using base(...);  // сделать доступными ВСЕ базовые конструкторы, не пересекающиеся по сигнатурам с собственными

  using base();             // сделать доступными только определенные сигнатуры.
  using base(Type1, Type2);
}


Код автоинициализированных полей компилятор вставляет в начало КАЖОГО конструктора и сейчас, т.е. он и так участвует в догенерировании кода конструкторов. Резюмируя все это — фича конечно неплохая, но только в случае явного управления ею.
Re[11]: Почему конструкторы не наследуются?
От: Дарней Россия  
Дата: 12.08.05 08:16
Оценка:
Здравствуйте, vdimas, Вы писали:

V>
V>class DerivedClass : BaseClass {
V>  using base(...);  // сделать доступными ВСЕ базовые конструкторы, не пересекающиеся по сигнатурам с собственными

V>  using base();             // сделать доступными только определенные сигнатуры.
V>  using base(Type1, Type2);
V>}
V>


V>Код автоинициализированных полей компилятор вставляет в начало КАЖОГО конструктора и сейчас, т.е. он и так участвует в догенерировании кода конструкторов. Резюмируя все это — фича конечно неплохая, но только в случае явного управления ею.


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