Для нашего примера мы предположим, что класс Manager расширяет Employee, обеспечивал запись числа опционов, а класс SalesPerson поддерживает информацию о числе продаж. В C# расширение класса задается в определении класса операцией, обозначаемой двоеточием (:). Так получаются производные типы класса в следующем фрагменте программного кода.
// Добавление двух подклассов в пространстве имен Employees.
namespace Employees {
public class Manager: Employee{
// Менеджер должен знать число опционов.
private ulong numberOfOptions;
public ulong NumbOpts {
get {return numberOfOptions;}
set {numberOfOptions = value;}
}
}
public class SalesPerson: Employee{
// Продавец должен знать число продаж.
private int numberOfSales;
public int NumbSales {
get {return numberOfSales;}
set {numberOfSales = value;}
}
}
}
Теперь, когда создано отношение подчиненности, SalesPerson и Manager автоматически наследуют все открытие (и защищенные) члены базового класса Employee. Например :
// Создание подкласса и доступ к функциональным возможностям
// базового класса.
static void Main (string[] args) {
// Создание экземпляра SalesPerson.
SalesPerson stan = new SalesPerson();
// Эти члены наследуют возможности базового класса Employee.
stan.ID = 100;
stan.Name = "Stan";
// Это определено классом SalesPerson.
stan.NumbSales = 42;
Console.ReadLine();
}
Следует знать, что наследование сохраняет инкапсуляцию. Поэтому производный класс не может иметь непосредственный доступ к приватным членам, определенным базовым классом.
Управление созданием базовых классов с помощью base
В настоящий момент SalesPerson и Manager можно создать только с помощью конструктора, заданного по умолчанию. Поэтому предположим, что в тип Manager добавлен новый конструктор с шестью аргументами, который вызывается так, как показано ниже.
static void Main(string[] args) {
// Предположим, что есть следующий конструктор с параметрами
// (имя, возраст, ID, плата, SSN, число опционов).
Manager chucky = new Manager("Chucky", 35, 92, 100000, "333-23-2322", 9000);
}
Если взглянуть на список аргументов, можно сразу понять, что большинство из них должно запоминаться в членах-переменных, определенных базовым классом Employee. Для этого вы могли бы реализовать этот конструктор так, как предлагается ниже.
// Если не указано иное, конструктор подкласса автоматически вызывает
// конструктор базового класса, заданный по умолчанию.
public Manager(string fullName, int age, int empID, float currPay, string ssn, ulong numbOfOpts) {
// Это наш элемент данных.
numberOfOptions = numbOfOpts;
// Использование членов, наследуемых от Employee,
// для установки данных состояния.
ID = empID;
Age = age;
Name = fullName;
SocialSecurityNumber = ssn;
Pay = currPay;
}
Строго говоря, это допустимый, но не оптимальный вариант. В C#, если вы не укажете иное, конструктор базового класса, заданный по умолчанию, вызывается автоматически до выполнения логики любого пользовательского конструктора Manager. После этого текущая реализация получает доступ к множеству открытых свойств базового класса Employee, чтобы задать его состояние. Поэтому здесь при создании производного объекта вы на самом деле "убиваете семь зайцев" (пять наследуемых свойств и два вызова конструктора)!
Чтобы оптимизировать создание производного класса, вы должны реализовать свои конструкторы подклассов так, чтобы явно вызвался подходящий пользовательский конструктор базового класса, а не конструктор, заданный по умолчанию. Таким образом можно уменьшить число вызовов инициализации наследуемых членов (что экономит время). Позвольте для этого модифицировать пользовательский конструктор.
// На этот раз используем ключевое слово C# "base" для вызова
// пользовательского конструктора с базовым классом.
public Manager (string fullName, int age, int empID, float currPay, string ssn, ulong numbOfOpts): base(fullName, age, empID, currPay, ssn){
numberOfOptions = numbOfOpts;
}
Здесь конструктор был дополнен довольно запутанными элементами синтаксиса. Непосредственно после закрывающей скобки списка аргументов конcтруктора стоит двоеточие, за которым следует ключевое слово C# base. В этой ситуации вы явно вызываете конструктор с пятью аргументами, определенный классом Employees избавляясь от ненужных вызовов в процессе создания дочернего класса.
Читать дальше