C# 编程/继承
继承的好处是什么?
- 它为你节省了很多打字。
- 它可以避免你重复自己。
继承的类比解释
假设你想创建一个鹰、一只猎鹰和一只秃鹫。为了创建这些飞行动物,你注意到这些生物都有以下特点:
- 飞行
- 繁殖
- 进食
假设这三种类型的鸟类以完全相同的方式飞行、繁殖和进食。
如果没有继承,你将被迫复制代码。即,让鹰飞行的相同代码也将被复制以使秃鹫飞翔。对于程序员来说,这是一个公理——他们是一群懒惰的人,不想重复自己——重复几乎总是件坏事。
请注意,鹰、猎鹰和秃鹫实际上都是鸟类。因此,可以说鸟类通常总是有进食、繁殖和飞行的特征。所以,使用“继承”,你可以创建一个通用的“鸟类”原型,它可以进食、繁殖和飞行,然后定义好后,你可以让所有其他特定的鸟类继承这些特征。换句话说,使用原型,你可以根据这个原型设计其他特定的鸟类。
这意味着猎鹰会自动知道如何飞行,因为它从通用“鸟类”类继承了这种行为。你基本上不必重复自己。
继承是能够从另一个类(“父”类)创建类,扩展父类在派生类或“子”类中的功能和状态的能力。它允许派生类重载来自其父类的函数。
继承是面向对象编程的支柱之一。它是从另一个类设计一个类的机制,是代码可重用的理念之一,支持层次分类的概念。C# 程序由类组成,其中新的类可以从头开始创建,也可以使用现有类的某些或所有属性来创建。
与继承和代码可重用性相关的另一个特性是多态性,它允许对不同数据类型进行不同操作时使用相同的函数名称。因此,C# 通过这两个特性支持代码可重用性。
继承的重要特征包括:
- 派生类扩展其基类。也就是说,它包含其父类的函数和数据,并且它还可以包含自己的数据成员和函数。
- 派生类不能更改继承成员的定义。
- 构造函数和析构函数不会被继承。基类的所有其他成员都会被继承。
- 派生类中成员的可访问性取决于其在基类中声明的可访问性。
- 派生类可以重写继承的成员。
继承的示例
using System;
using System.Text;
namespace ContainmentInheritance
{
class Room
{
public int length;
public int width;
public int height;
public Room(int l, int w, int h)
{
length = l;
width = w;
height = h;
}
}
class Home
{
int numberOfRooms;
int plotSize;
string locality;
string name;
// create an object of class Room inside class Home
Room studyRoom = new Room(10, 12, 12);
public Home()
{
numberOfRooms = 1;
plotSize = 1000;
locality = "Versova";
name = "study room";
}
public void Display()
{
Console.WriteLine("MyHome has {0} rooms", numberOfRooms);
Console.WriteLine("Plot size is {0}", plotSize);
Console.WriteLine("Locality is {0}", locality);
int area = studyRoom.length*studyRoom.width;
Console.WriteLine("Area of the {0} room is {1}", name, area);
}
}
class Program
{
static void Main(string[] args)
{
Home myhome = new Home();
myhome.Display();
Console.ReadLine();
}
}
}
下面的代码示例展示了两个类,Employee
和 Executive
。 Employee
具有 GetPayCheck
和 Work
函数。
我们希望 Executive
类拥有相同的函数,但实现方式不同,并且有一个额外的函数,AdministerEmployee
。
以下是第一个要派生的类的创建。
public class Employee
{
// We declare one method virtual so that the Executive class can
// override it.
public virtual void GetPayCheck()
{
// Get paycheck logic here.
}
//Employee's and Executives both work, so no virtual here needed.
public void Work()
{
// Do work logic here.
}
}
现在,我们创建一个 Executive
类,它将覆盖 GetPayCheck
函数
public class Executive : Employee
{
// The override keyword indicates we want new logic behind the GetPayCheck method.
public override void GetPayCheck()
{
// New getpaycheck logic here.
}
// The extra method is implemented.
public void AdministerEmployee()
{
// Manage employee logic here
}
}
你会注意到,Executive
类中没有 Work
函数,因为它继承自 Employee
。
static void Main(string[] args)
{
Employee emp = new Employee();
Executive exec = new Executive();
emp.Work();
exec.Work();
emp.GetPayCheck();
exec.GetPayCheck();
exec.AdministerEmployee();
}
如果基类包含一个虚方法,它在其他地方调用该方法,并且派生类覆盖了该虚方法,那么基类实际上会调用派生类的函数。
public class Resource : IDisposable
{
private bool _isClosed = false; // good programming practice initialise, although default
protected virtual void Close()
{
Console.WriteLine("Base resource closer called!");
}
~Resource()
{
Dispose();
}
public void Dispose()
{
if (!_isClosed)
{
Console.WriteLine("Disposing resource and calling the Close() method...");
_isClosed = true;
Close();
}
}
}
public class AnotherTypeOfResource : Resource
{
protected override void Close()
{
Console.WriteLine("Another type of resource closer called!");
}
}
public class VirtualMethodDemo
{
public static void Main()
{
Resource res = new Resource();
AnotherTypeOfResource res2 = new AnotherTypeOfResource();
res.Dispose(); // Resource.Close() will be called.
res2.Dispose(); // Even though Dispose() is part of the Resource class,
// the Resource class will call AnotherTypeOfResource.Close()!
}
}
派生类不会自动继承基类的构造函数,并且它无法实例化,除非它提供自己的构造函数。派生类必须使用 base 关键字调用其基类的构造函数之一。
public class MyBaseClass
{
public MyBaseClass(string text)
{
console.WriteLine(text);
}
}
public class MyDerivedClass : MyBaseClass
{
public MyDerivedClass(int number)
: base(number.ToString())
{ }
public MyDerivedClass(string text) // even though this is exactly the same as MyBaseClass'
// only constructor, this is still necessary as constructors are not inherited.
: base(text)
{ }
}
C# 从另一个类继承的语法方法是使用 :
运算符。
示例
public class Executive : Employee
要指示可以重写的函数,请使用 virtual 标记函数。
public virtual void Write(string text)
{
System.Console.WriteLine("Text:{0}", text);
}
要覆盖一个函数,请使用 override
关键字
public override void Write(string text)
{
System.Console.WriteLine(text);
}
派生函数中缺少 new
或 override
关键字可能会导致编译期间出现错误或警告:[1] 以下是一个示例
abstract class ShapesA
{
abstract public int Area(); // abstract!
}
class Square : ShapesA
{
int x, y;
public int Area() // Error: missing 'override' or 'new'
{
return x * y;
}
}
class Shapes
{
virtual public int Area() { return 0; } // it is virtual now!
}
class Square : Shapes
{
int x, y;
public int Area() // no explicit 'override' or 'new' required
{ return x * y; }
}
Square
类函数 Area()
将导致编译错误,如果它从 ShapesA
类派生
error CS0534: 'ConsoleApplication3.Square' does not implement inherited abstract member 'ConsoleApplication3.Shapes.Area()'
如果从普通的 Shapes
类派生,则相同的函数会导致编译警告
warning CS0114: 'ConsoleApplication3.Square.Area()' hides inherited member 'ConsoleApplication3.Shapes.Area()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword.
- ↑ Greg Beech (2010-03-09). "C# 设计:为什么抽象方法需要 new/override,而虚拟方法不需要? / 答案". http://efreedom.com/: eFreedom. 检索于 2011-08-11.
使用 .NET 3.5 SP1 中附带的 C# 3.0 编译器或 .NET 4.0 中附带的 C# 4.0 编译器,我都会在你的第一个例子中收到以下错误:[...],在第二个例子中收到以下警告:[...]。在第一个例子中,这是一个错误,因为你实际上并没有重写基方法,这意味着在具体类中没有抽象方法的实现。在第二个例子中,这是一个警告,因为代码在技术上是正确的,但编译器怀疑这不是你想要的。这是通常启用“将警告视为错误”编译设置的一个原因。
{{cite web}}
: 外部链接在
(帮助)|location=