Здравствуйте, Juiceek, Вы писали:
J>Почему не наследуются конструкторы?
Потому что так предписано стандартом.
10.3.3 Inheritance
A class inherits the members of its direct base class type. Inheritance means that a class implicitly contains all members of its direct base class type, except for the instance constructors, destructors and static constructors of the base class.
Здравствуйте, nikov, Вы писали:
N>Здравствуйте, Juiceek, Вы писали:
J>>Почему не наследуются конструкторы?
N>Потому что так предписано стандартом.
N>
N>10.3.3 Inheritance
N>A class inherits the members of its direct base class type. Inheritance means that a class implicitly contains all members of its direct base class type, except for the instance constructors, destructors and static constructors of the base class.
Да, но есть же все-таки определенная логика в этом?
Я вот все думаю и никак не могу придумать, что бы могло помешать этому.
Здравствуйте, Juiceek, Вы писали:
J>Да, но есть же все-таки определенная логика в этом? J>Я вот все думаю и никак не могу придумать, что бы могло помешать этому.
Есть. ИМХО, польза така: наследуемые конструкторы могут помочь только в случае, когда в наследниках не требуется "переопределять" (дополнять, добавлять какую-то логику) унаследованные конструкторы, что встречается катострафически редко, например, в собственных исключениях:
[Serializable]
public class MyException : Exception
{
public MyException() { }
public MyException(string message) : base(message) { }
public MyException(string message, Exception inner) : base(message, inner) { }
protected MyException(SerializationInfo info, StreamingContext context) : base(info, context) { }
}
В большенстве же случаях наследники добавляют к базовому классу члены, которые непло хо бы инициализировать какими-то значениями в конструкторе => конструкторы по-любому придётся "переопределять". Так же очень часто (по моим наблюдениям) в наследниках не требуются многие конструкторы предков => нужен был бы синтаксис явного "скрытия" базовых конструкторов или же изменения им области видимости. Тогда бы кто-то потребовал бы такой же "фенечки" и для методов, что выглядело бы глупо.
В общем, из альтернативы "явное объявление конструктора" и "явное запрещение\ограничение конструктора" было выбрано первое хотя бы даже из-за меньшей очевидности последнего.
Подобной функциональности не сложно добиться (если её ещё нет) в Nemerle, например.
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, Juiceek, Вы писали:
J>Да, но есть же все-таки определенная логика в этом? J>Я вот все думаю и никак не могу придумать, что бы могло помешать этому.
Да, логика есть. Допустим есть цепочка наследования Derived : Base. Если бы конструкторы наследовались, то при вызове конструктора в виде Derived d = new Derived(...), overload resolution производился бы среди множества, содержащего как конструкторы, определенные в классе Derived, так и унаследованные им от класса Base. Если overload resolution выбирает конструктор класса Base, то что должно произойти? Можно представить два варианта:
1) Создается экземпляр класса Base и вызывается выбранный конструктор, определенный в классе Base. Это плохо, потому что полученный объект нельзя было бы присвоить переменной d, которая имеет тип Derived.
2) Создается экземпляр класса Derived и вызывается выбранный конструктор, определенный в классе Base. Это тоже не всегда хорошо, потому что этот конструктор ничего не знает о полях, добавленных в классе Derived, и они не будут инициализированы никакими осмысленными значениями, а просто будут иметь значения по умолчанию. Если это поведение является желательным, то в класс Derived нужно явно добавить конструктор с такой же сигнатурой, как конструктор класса Base, просто делегирующий вызов базовому классу с помощью constructor-initializer в виде : base(...).
Другими словами, назначение этого правила — снизить риск ошибок при вызове конструкторов, и сделать семантику более ясной.
Здравствуйте, Lloyd, Вы писали:
_M_>>кто вам такое сказал?
L>А неушто наследуются?
хм, если не наследуются, почему тогда в следующем примере, во всех случаях, отрабатывает конструктор базового класса?
using System;
public class A
{
public A()
{
Console.WriteLine("A()");
}
public A(string str)
{
Console.WriteLine("A(string): {0}", str);
}
}
public class B : A
{
public B()
{
Console.WriteLine("B()");
}
}
public class C : A
{
public C() : base()
{
Console.WriteLine("C()");
}
}
public class D : A
{
public D(string str)
{
Console.WriteLine("D(string): {0}", str);
}
}
public class E : A
{
public E(string str) : base(str)
{
Console.WriteLine("E(string): {0}", str);
}
}
class Program
{
static void Main()
{
Console.WriteLine("==implicit no params==");
B b = new B();
Console.WriteLine("==explicit no params==");
C c = new C();
Console.WriteLine("==implicit with params==");
D d = new D("paramStr");
Console.WriteLine("==explicit with params==");
E e = new E("paramStr");
}
}
результат:
==implicit no params==
A()
B()
==explicit no params==
A()
C()
==implicit with params==
A()
D(string): paramStr
==explicit with params==
A(string): paramStr
E(string): paramStr
на мой взгляд, если бы не наследовался конструктор — были бы проблемы, т.к. если конструктор базового класса не отработает, то какието поля определенные в базовом классе как private могут быть не инициализированы, а из наследника они будут недоступны, что сделает наследника непригодным к использованию...
Здравствуйте, _Morpheus_, Вы писали:
_M_>на мой взгляд, если бы не наследовался конструктор — были бы проблемы, т.к. если конструктор базового класса не отработает, то какието поля определенные в базовом классе как private могут быть не инициализированы, а из наследника они будут недоступны, что сделает наследника непригодным к использованию...
Значит так и запишем, что значит "наследуется" ты не знаешь.
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, _Morpheus_, Вы писали:
_M_>>на мой взгляд, если бы не наследовался конструктор — были бы проблемы, т.к. если конструктор базового класса не отработает, то какието поля определенные в базовом классе как private могут быть не инициализированы, а из наследника они будут недоступны, что сделает наследника непригодным к использованию...
L>Значит так и запишем, что значит "наследуется" ты не знаешь.
Здравствуйте, _Morpheus_, Вы писали:
_M_>хм, если не наследуются, почему тогда в следующем примере, во всех случаях, отрабатывает конструктор базового класса?
_M_>на мой взгляд, если бы не наследовался конструктор — были бы проблемы, т.к. если конструктор базового класса не отработает, то какието поля определенные в базовом классе как private могут быть не инициализированы, а из наследника они будут недоступны, что сделает наследника непригодным к использованию...
Конструктор базового класса отрабатывает не потому, что он наследуется, а потому что он неявно вызывается из конструктора производного класса в силу следующего правила:
10.11.1 Constructor initializers
.......
If an instance constructor has no constructor initializer, a constructor initializer of the form base() is implicitly provided. Thus, an instance constructor declaration of the form
Здравствуйте, _Morpheus_, Вы писали:
_M_>ну так просвяти неграмотных
class A {
public A() {}
public A(string text) {}
public A(int number) {}
public void Method() {}
}
class B : A {
}
static class Program
{
static void Main() {
var b = new B(); // Это вызов не унаследованного, а созданного в B компилятором конструктора класса B
b.Method(); // Это вызов унаследованного метода из класса A.
// Сигнатура этого метода, его наличие вообще, тип возвращаемого параметра и т.п. могут быть
// изменены в классе A без переделки класса B, так как метод "принадлежит" A, а B его никак не использует.
// Для сравнения: скрытие конструктора по-умолчанию у А потребует передки класса B.
// Так как конструкторы не наследуются, то следующие вызовы не корректныvar b2 = new B("test");
var b3 = new B(4);
}
}
Если бы конструкторы наследовались, то вызовы
var b2 = new B("test");
var b3 = new B(4);
были бы корректными. Так же добавление нового конструктора _к А_, например
public A(string text, int number) {}
позволило бы создавать экземпляры B (и других классов-наследников) вот так:
var b4 = new B("test", 8);
без изменения кода классов-наследников (в даннос случае без изменения кода класса В), по аналогии с добавлением нового открытого метода к классу А, который можно вызывать через всех наследников без изменения их кода.
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, Lloyd, Вы писали:
L>>>Значит так и запишем, что значит "наследуется" ты не знаешь.
_M_>>ну так просвяти неграмотных
L>здесь
что такое наследование я знаю, по теме там ответа не нашел,
я спрашивал почему наследования конструктора нет, несмотря на то, что в следующем коде конструктор наследуется:
public class B : A
{
public B(string str) : base(str)
{
}
}
насколько я понял, речь шла несколько о другом — о том что если конструктор явно не наследуется, то в наследниках он не доступен...
Здравствуйте, _Morpheus_, Вы писали:
L>>здесь
_M_>что такое наследование я знаю, по теме там ответа не нашел,
Видимо не совсем.
_M_>я спрашивал почему наследования конструктора нет, несмотря на то, что в следующем коде конструктор наследуется: _M_>public class B : A _M_>{ _M_> public B(string str) : base(str) _M_> { _M_> } _M_>}
Здравствуйте, _Morpheus_, Вы писали:
L>>Это никакое не наследование. Это тупо вызов.
_M_>а какое отношение к этому "тупо вызов" имеет синтаксис наследования?
Какой еще "синтаксис наследования" ты о чем вообще?