Наследование и полиморфизм
Явное обращение к конструктору базового класса
Продолжаем совершенствовать наши классы A и B. Очередная задача – выяснить способы передачи управления конструктору базового класса при создании объекта — представителя производного класса.
Таким образом, передача управления конструктору базового класса осуществляется посредством конструкции
...(...):base(...){...},
которая располагается в объявлении конструктора класса-наследника между заголовком конструктора и телом. После ключевого слова base в скобках располагается список значений параметров конструктора базового класса. Очевидно, что выбор соответствующего конструктора определяется типом значений в списке (возможно, пустом) параметров:
using System; /*private*/ class X { } /*public*/ class A { public A(){val2_A = 0; val3_A = 0;} // К этому конструктору также можно обратиться из производного класса. protected A(int key):this() {val1_A = key;} // А вот этот конструктор предназначен исключительно // для внутреннего использования. private A(int key1,int key2,int key3) {val1_A = key1; val2_A = key2; val3_A = key3;} public int val1_A = 0; public void fun1_A (String str) { Console.WriteLine("A's fun1_A:" + str); this.fun2_A("private function from A:"); fun3_A(); } private void fun2_A (String str) { Console.WriteLine(str + "A's fun2_A:" + val2_A.ToString()); } protected int val3_A; private void fun3_A () { A a = new A(1,2,3); a.fun2_A("Это наше внутреннее дело!"); } } /*public*/ class B:A { // Явные обращения к конструкторам базового класса. public B():base(){val1_B = 0;} public B(int key):base(key){val1_B = key;} } class Class1 { static void Main(string[] args) { B b0 = new B(125); } }Листинг 7.1.
Для создания объектов в программе можно применять конструкторы следующих степеней защиты:
public – при создании объектов в рамках данного пространства имен, в методах любого класса — члена данного пространства имен;
protected – при создании объектов в рамках производного класса, в том числе при построении объектов производного класса, а также для внутреннего использования классом — владельцем данного конструктора;
private – применяется исключительно для внутреннего использования классом-владельцем данного конструктора.
Кто строит БАЗОВЫЙ ЭЛЕМЕНТ
Теперь (в рамках того же приложения) построим два новых класса:
class X { } class Y:X { } // Это уже в Main() Y y = new Y();
Вся работа по созданию объекта – представителя класса Y при явном отсутствии конструкторов по умолчанию возлагается на КОНСТРУКТОРЫ УМОЛЧАНИЯ – те самые, которые самостоятельно строит транслятор.
Особых проблем не будет, если в производном классе явным образом начать объявлять конструкторы:
class X { } class Y:X { public Y(int key){} public Y(){} } // Это уже в Main() Y y0 = new Y(); Y y1 = new Y(125);
С этого момента в производном классе нет больше конструктора умолчания. Теперь все зависит от соответствия оператора определения объекта построенному нами конструктору.
Объявим в производном классе оба варианта конструкторов. И опять все хорошо. Конструктор умолчания базового класса (тот, который строится транслятором) продолжает исправно выполнять свою работу.
Проблемы в производном классе возникнут, если в базовом классе попытаться объявить вариант конструктора с параметрами:
class X { public X(int key){} } class Y:X { public Y(int key){} // Нет конструктора умолчания базового класса! public Y(){} // Нет конструктора умолчания базового класса! } // Это уже в Main() Y y0 = new Y(); Y y1 = new Y(125);
И здесь транслятор начнет обижаться на конструкторы производного класса, требуя ЯВНОГО объявления конструктора базового класса БЕЗ параметров. Если вспомнить, что при ЛЮБОМ вмешательстве в дело построения конструкторов транслятор снимает с себя всю ответственность, причина негодования транслятора становится очевидной. Возможны два варианта решения проблемы:
- явным образом заставить работать новый конструктор базового класса,
- самостоятельно объявить новый вариант конструктора без параметров:
class X { public X(){} public X(int key){} } class Y:X { public Y(int key){} public Y():base(125){} } // Это уже в Main() Y y0 = new Y(); Y y1 = new Y(125);