Доступ к элементам базового класса из производного класса
Производный класс, заменяющий или переопределяет метод базового класса или свойство, по-прежнему может получить доступ к методу или свойству базового класса с помощью ключевого слова base. Это позволяет вызывать конструкторы базового класса, методы и свойства из переопределенных членов производного класса. Используя ключевое слово base, можно убедиться, что производный класс правильно использует и расширяет функциональные возможности, предоставляемые базовым классом.
Ключевое слово base используется для выполнения следующих задач:
- Вызов метода базового класса из переопределенного метода производного класса.
- Реализация конструктора базового класса из конструктора производного класса.
Ключевое слово base имеет следующие ограничения:
- Ключевое слово
baseможно использовать только в конструкторе, методе экземпляра или методе доступа к свойству экземпляра. - Ключевое слово
baseнельзя использовать в статическом методе. Попытка использовать ключевое словоbaseв статическом методе приведет к возникновению ошибки.
При реализации ключевого слова base в производном классе код использует базовый класс, указанный в объявлении класса. Например, если в объявлении класса указано ClassC : ClassB класса, ключевое слово base позволяет коду получать доступ к элементам ClassB из ClassC. Не имеет значения, наследуется ли класс ClassB от класса ClassA.
Доступ к свойствам и методам базового класса из производного класса
Доступ к свойствам и методам базового класса из производного класса является общим требованием при реализации наследования. Следующий код демонстрирует синтаксис реализации ключевого слова base:
base.MemberName
Обратите внимание, что ключевое слово base и имя элемента базового класса разделяются точкой (.).
MemberName может быть свойством, методом или полем базового класса.
В следующем коде показано, как получить доступ к свойствам и методам базового класса из производного класса:
// create an instance of the derived classes
DerivedClass1 derivedClass1 = new DerivedClass1();
// demonstrate the overridden methods of the derived class
Console.WriteLine("Calling the methods of DerivedClass1...\n");
Console.WriteLine($"Method1 in the derived class overrides the base class and provides a custom message: {derivedClass1.Method1()}");
derivedClass1.Method2();
/*Output:
Calling the methods of DerivedClass1...
Method1 in the base class is abstract and can't be called.
Method1 in the derived class overrides the base class and provides a custom message: Message from the overridden Method1 in DerivedClass1
Method2 in the derived class calls base.Method2 (reuses the base class implementation)
Method2 in the base class implements common behavior and returns true/false
Method2 in the derived class accesses base class Property2: Base - Property2
Method2 in the derived class uses base class members to modify and extend functionality
*/
public abstract class BaseClass
{
public abstract string Property1 { get; set; }
public virtual string Property2 { get; set; } = "Base - Property2";
public abstract string Method1();
public virtual bool Method2()
{
Console.WriteLine("Method2 in the base class implements common behavior and returns true/false");
return true;
}
}
public class DerivedClass1 : BaseClass
{
public override string Property1 { get; set; } = "Derived - Property1";
public new string Property2 { get; set; } = "Derived - Property2";
public override string Method1()
{
// Method1 of the base class is abstract and can't be called
Console.WriteLine($"Method1 in the base class is abstract and can't be called.");
// Return the base.Method1 response additional information specific to DerivedClass1
return $"Message from the overridden Method1 in DerivedClass1";
}
public override bool Method2()
{
// Call base class method to implement common behavior
Console.WriteLine($"\nMethod2 in the derived class calls base.Method2 (reuses the base class implementation)");
bool baseMethod2Success = base.Method2();
// Access base class Property2
string baseProperty2Value = base.Property2;
Console.WriteLine($"Method2 in the derived class accesses base class Property2: {baseProperty2Value}");
// implement derived class logic that involves base class information
if (baseMethod2Success && baseProperty2Value == "Base - Property2")
{
Console.WriteLine("\nMethod2 in the derived class uses base class members to modify and extend functionality");
return true;
}
else
{
Console.WriteLine("Method2 in the derived class can implement alternate behavior");
}
return false;
}
}
В этом примере кода класс DerivedClass1 наследует от BaseClass и переопределяет его методы для расширения их функциональных возможностей. Код реализует следующие действия:
Экземпляр
DerivedClass1создается с помощью инструкцииDerivedClass1 derivedClass1 = new DerivedClass1();. Этот экземпляр производного класса используется для вызова и демонстрации переопределенных методов производного класса.Код вызывает
Method1производного класса из оператораConsole.WriteLine. ПереопределенныйMethod1не может получить доступ к абстрактуMethod1базового класса. Вместо этого она предоставляет собственную реализацию, которая возвращает строку, указывающую, что она уникальна для производного класса.Код вызывает
Method2производного класса. ПереопределенныйMethod2используетbase.Method2для повторного использованияMethod2реализации базового класса. Метод обращается кProperty2базового класса и выводит его значение. Затем переопределенный метод использует логическое значение, возвращаемоеMethod2базового класса, и значениеProperty2, чтобы расширить функциональностьMethod2или реализовать альтернативное поведение. На этом шаге показано, как производный класс может создавать и изменять поведение метода базового класса.
Заметка
Рекомендуется использовать base виртуальных членов для вызова реализации базового класса этого члена в собственной реализации. Разрешение поведения базового класса позволяет производным классам сосредоточиться на реализации поведения, конкретного для производного класса. Если реализация базового класса не вызывается, то он до производного класса, чтобы обеспечить совместимость их поведения с поведением базового класса.
Доступ к конструкторам базового класса из производного класса
Конструкторы классов в базовом классе можно получить из конструкторов производного класса с помощью ключевого слова base.
В следующем коде показано, как получить доступ к конструкторам базового класса из производного класса:
// create an instance of the derived classes
DerivedClass1 derivedClass1 = new DerivedClass1("Derived1 - Property1", "Derived1 - Property2");
// demonstrate the overridden methods of the derived class
Console.WriteLine("Calling the methods of DerivedClass1...\n");
Console.WriteLine($"Method1 in the derived class appends derived class information to the return value: {derivedClass1.Method1()}");
derivedClass1.Method2();
/*Output:
Calling the methods of DerivedClass1...
Method1 in the derived class calls base.Method1. base.Method1 returns: base.Method1 results
Method1 in the derived class appends derived class information to the return value: base.Method1 results - plus information specific to DerivedClass1
Method2 in the derived class calls base.Method2 (reuses the base class implementation)
Method2 in the base class implements common behavior and returns true/false
Method2 in the derived class accesses base class Property2: Base - Property2
Method2 in the derived class uses base class members to modify and extend functionality
*/
public abstract class BaseClass
{
public abstract string Property1 { get; set; }
public virtual string Property2 { get; set; }
public BaseClass(string property1, string property2)
{
Property1 = property1;
Property2 = property2;
}
public virtual string Method1()
{
return "base.Method1 results";
}
public virtual bool Method2()
{
Console.WriteLine("Method2 in the base class implements common behavior and returns true/false");
return true;
}
}
public class DerivedClass1 : BaseClass
{
public override string Property1 { get; set; }
public new string Property2 { get; set; }
public DerivedClass1(string property1, string property2) : base(property1, "Base - Property2")
{
Property1 = property1;
Property2 = property2;
}
public override string Method1()
{
// Method1 of the base class is now virtual
Console.WriteLine($"Method1 in the derived class calls base.Method1. base.Method1 returns: {base.Method1()}");
// Return the base.Method1 response additional information specific to DerivedClass1
return $"{base.Method1()} - plus information specific to DerivedClass1";
}
public override bool Method2()
{
// Call base class method to implement common behavior
Console.WriteLine($"\nMethod2 in the derived class calls base.Method2 (reuses the base class implementation)");
bool baseMethod1Success = base.Method2();
// Access base class Property2
string baseProperty2Value = base.Property2;
Console.WriteLine($"Method2 in the derived class accesses base class Property2: {baseProperty2Value}");
// implement derived class logic that involves base class information
if (baseMethod1Success && baseProperty2Value == "Base - Property2")
{
Console.WriteLine("\nMethod2 in the derived class uses base class members to modify and extend functionality");
return true;
}
else
{
Console.WriteLine("Method2 in the derived class can implement alternate behavior");
}
return false;
}
}
Вызов конструктора базового класса из производного конструктора классов важен. Например, когда конструктор базового класса инициализирует общие свойства, используемые производным классом. Вызывая конструктор базового класса из конструктора производных классов, необходимо убедиться, что общие свойства инициализированы до выполнения конструктора производных классов.
Рассмотрим следующий код:
public abstract class Vehicle
{
public virtual int Speed { get; set; }
public virtual int Fuel { get; set; }
public Vehicle(int speed, int fuel)
{
Speed = speed;
Fuel = fuel;
}
public virtual void Drive()
{
Console.WriteLine("Vehicle is driving");
}
}
public class Car : Vehicle
{
public int NumberOfDoors { get; set; }
public int TrunkCapacity { get; set; }
public Car(int speed, int fuel, int numberOfDoors) : base(speed, fuel)
{
NumberOfDoors = numberOfDoors;
// Initialize TrunkCapacity based on the Speed and Fuel properties of the base class
TrunkCapacity = CalculateTrunkCapacity(Speed, Fuel);
}
private int CalculateTrunkCapacity(int speed, int fuel)
{
// Example logic to calculate trunk capacity based on speed and fuel
return (speed + fuel) / 2;
}
public override void Drive()
{
base.Drive();
Console.WriteLine("Car is driving with additional features");
}
}
class Program
{
static void Main()
{
Car car = new Car(100, 50, 4);
Console.WriteLine($"Speed: {car.Speed}, Fuel: {car.Fuel}, NumberOfDoors: {car.NumberOfDoors}, TrunkCapacity: {car.TrunkCapacity}");
car.Drive();
}
}
Обратите внимание, что конструктор классов Car вызывает конструктор базового класса с помощью ключевого слова base. Вызов конструктора базового класса сначала гарантирует правильность инициализации свойств Speed и Fuel базового класса Vehicle перед выполнением конструктора классов Car. Эта последовательность событий важна, так как свойство TrunkCapacity класса Car инициализируется с помощью свойств Speed и Fuel базового класса Vehicle.
Сводка
При доступе к членам базового класса из производного класса следует учитывать следующие рекомендации.
- Используйте ключевое слово
baseдля доступа к членам базового класса из производного класса. - Используйте ключевое слово
baseдля вызова конструкторов базового класса из производных конструкторов классов. - Используйте ключевое слово
baseдля доступа к полям базового класса, свойствам и методам из переопределенных методов в производном классе.