C# 继承

C# 继承

  • 继承的类型
  • 实现继承
  • 虚方法
  • 隐藏方法
  • 调用函数的基类版本
  • 抽象类和抽象函数
  • 密封类和密封方法
  • 派生类的构造函数
  • 修饰符
    • 访问修饰符
    • 其他修饰符
  • 接口

继承的类型

  • 实现继承
    表示一个类型派生于一个基类型,拥有该基类型的所有成员字段和函数。在实现继承中,派生类型的每个函数采用基类型的实现代码,除非在派生类型的定义中指定重写该函数的实现代码。
  • 接口继承
    表示一个类型只继承了函数的签名,没有继承任何实现代码。在需要指定该类型具
    有某些可用的特性时,最好使用这种类型的继承。
  • 多重继承
    一些语言如 C++支持所谓的"多重继承",即一个类派生于多个类。
  • 结构和类
    结构(值类型)和类(引用类型)。使用结构的一个限制是结构不支持继承,但每个结构都自动派生于 System.ValueType。实际上还应更仔细一些:不能建立结构的类型层次,但结构可以实现接口。换言之,结构并不支持实现继承,但支持接口继承。事实上,定义结构和类可以总结为:
    • 结构总是派生于 System.ValueType,它们还可以派生于任意多个接口。
    • 类总是派生于用户选择的另一个类,它们还可以派生于任意多个接口。

实现继承

声明一个类派生于另一个类,可以使用下面的语法:

class MyClass : MyBaseClass
{
	// 函数和数据成员
}

声明一个类继承其他类和接口

class MyClass : MyBaseClass, IMyInterface1, IMyInterface2
{
	// 函数和数据成员
}

声明一个结构继承其他接口

struct MyStruct : IMyInterface1, IMyInterface2
{
	// ...
}

虚方法

把一个基类函数声明为 virtual,该函数就可以在派生类中重写了:

class MyBaseClass
{
	public virtual string VirtualMethod()
	{
		return "base method:VirtualMethod";
	}
}

把一个属性声明为virtual,对于虚属性或重写属性,语法与非虚属性是相同的,但要在定义中
加上关键字 virtual,其语法如下所示

public virtual string ForeName
{
	private string foreName;
	get { return foreName;}
	set { foreName = value;}
}

C#中虚函数的概念与标准 OOP 概念相同:可以在派生类中重写虚函数。在调用方法时,会调用对象类型的合适方法。在 C#中,函数在默认情况下不是虚拟的,但(除了构造函数以外)可以显式地声明为 virtual。

class MyClass : MyBaseClass
{
	public override string VirtualMethod()
	{
		return "override method:VirtualMethod";
	}
}

隐藏方法

如果签名相同的方法在基类和派生类中都进行了声明,但该方法没有声明为 virtual 和 override,派生类方法就会隐藏基类方法。在大多数情况下,是要重写方法,而不是隐藏方法,因为隐藏方法会存在为给定类的实例调用错误方法的危险。
假定有人编写了类 HisBaseClass:

class HisBaseClass
{
}

某一时刻编写了一个派生类,给 HisBaseClass 添加某个功能,特别是要添加一个目前基类中没有的方法 MyGroovyMethod():

class MyDerivedClass : HisBaseClass
{
	public int MyGroovyMethod()
	{
		return 0;
	}
}

一年后,基类的编写者决定扩展基类的功能。为了保持一致,他也添加了一个名为MyGroovyMethod()的方法,该方法的名称和签名与前面添加的方法相同,但并不完成相同的工作。在使用基类的新方法编译代码时,程序在应该调用哪个方法上就会有潜在的冲突。这在 C#中完全合法,但因为我们的 MyGroovyMethod()与基类的 MyGroovyMethod()不相关,运行这段代码的结果就可能不是我们希望的结果。C#已经为此设计了一种方式,可以很好地处理这种情况。
首先,系统会发出警告。在 C#中,应使用 new 关键字声明我们要隐藏一个方法,如下所示:

class MyDerivedClass: HisBaseClass
{
	public new int MyGroovyMethod()
	{
		return 0;
	}
}

调用函数的基类版本

C#有一种特殊的语法用于从派生类中调用方法的基类版本:base.< MethodName >()。

class CustomerAccount
{
	public virtual decimal CalculatePrice()
	{
		return 0.0M;
	}
}

class GoldAccount : CustomerAccount
{
	public override decimal CalculatePrice()
	{
		return base.CalculatePrice() * 0.8M;
	}
}

抽象类和抽象函数

C#允许把类和函数声明为 abstract,抽象类不能实例化,而抽象函数没有执行代码,必须在非抽
象的派生类中重写。显然,抽象函数也是虚拟的(但也不需要提供 virtual 关键字,实际上,如果提供了该关键字,就会产生一个语法错误)。如果类包含抽象函数,该类将也是抽象的,也必须声明为抽象的:

abstract class Building	// 抽象类
{
	private bool damaged = false; // 成员字段初始值
	public abstract decimal CalculateHeatingCost(); // 抽象方法
}

密封类和密封方法

C#允许把类和方法声明为 sealed。对于类来说,这表示不能继承该类;对于方法来说,这表示不能重写该方法。sealed 与java中的final相同。

sealed class FinalClass
{
	//....
}
FinalClass 类不能被其他类继承

class MyClass
{
	public sealed void FinalMethod()
	{
	}
}
FinalMethod不能再MyClass的派生类中重写。

派生类的构造函数

  1. 在层次结构中添加无参数的构造函数
public abstract class GenericCustomer
{
	private string name;
	public GenericCustomer()
	:base() // 使用base表示这是基类构造函数
	{
		name = "< no name >";
	}
	
}
  1. 在层次结构中添加带参数的构造函数
abstract class GenericCutomer
{
	private string name;
	public GenericCutomer(string name)
	{
		this.name = name;
	}
}
class Nevermore60Customer : GenericCutomer
{
	public Nevermore60Customer(string name, string referrerName)
	:base(name)
	{
		this.referrerName = referrerName;
	}
	private string referrerName;
	private uint highCostMinutesUesd;
}

修饰符

访问修饰符

C# 继承_第1张图片

其他修饰符

C# 继承_第2张图片

接口

接口有interface声明

public interface IDisposable
{
	void Dispose();
}

类派生接口

class SomeClass:IDisposable
{
	public void Dispose()
	{
		// 实现接口方法
	}
}

接口的定义

namespace Wrox.ProCSharp
{
	public interface IBankAccount
	{
		void PlayIn(decimal amount);
		bool Withdraw(decimal amount);
		decimal Balance
		{
			get;
		}
	}

}

接口的继承

namespace Wrox.ProCSharp.VenusBank
{
	public class SaverAccount : IBankAccount
	{
		private decimal balance;
		public void PayIn(decimal amount)
		{
			balance += amount;	
		}
		public bool Withdraw(decimal amount)
		{
			if (balance >= amount)
			{
				balance -= amount;
				return true;
			}
			Console.WriteLine("error.");
			return false;
		}
		public decimal Balance
		{
			get 
			{
				return balance;	
			}
		}
		public override string ToString()
		{
			return String.Format("Vens Bank Saver: Balance = {0,6:C}", balance);
		}
	}

}

不同类实现相同的接口

namespace Wrox.ProCSharp.JupiterBank 
{
	public class GoldAccount:IBankAccount
	{
		// ...
	}
}

测试代码

using System;
using Wrox.ProCSharp;
using Wrox.ProCSharp.VenusBank;
using Wrox.ProCSharp.JupiterBank;

namespace Wrox.ProCSharp
{
	class MainEntryPoint
	{
		static void Main(string[] args)
		{
			IBankAccount venusAccount = new SaverAccount();
			IBankAccount jupiterAccount = new GoldAccount();
			venusAccount.PayIn(200);
			venusAccount.Withdraw(100);
			Console.WriteLine(venusAccount.ToString());
			jupiterAccount.PayIn(500);
			jupiterAccount.Withdraw(600);
			jupiterAccount.Withdraw(100);
			Console.WriteLine(jupiterAccount.ToString());
		}
	}
}

接口数组

IBankAccount[] accounts = new IBankAccount[2];

accounts[0] = new SaverAccount();
accounts[1] = new GoldAccount();

派生接口
接口可以彼此继承,其方式与类的继承相同。

namespace Wrox.ProCSharp
{
	public interface ITransferBankAccount: IBankAccount
	{
		bool TransferTo(IBankAccount desination, decimal amount);
	}
}

派生接口类

public class CurrentAccount : ITransferBankAccount
{
	private decimal balance;
	public void PayIn(decimal amount)
	{
		balance += amount;
	}
	public bool Withdraw(decimal amount)
	{
		if (balance >= amount)
		{
			balance -= amount;
			return true;
		}
		Console.WriteLine("Withdrawal failed.");
		return false;
	}
	public decimal Balance
	{
		get { return balance;}
	}
	public bool TransferTo(IBankAccount destination, decimal amount)
	{
		bool result;
		if ((result = Withdraw(amount)) == true)
		{
			destination.PayIn(amount);
			return result;
		}
	}
	
	public override string ToString()
	{
		return String.Format("Jupiter Bank Current Account:Balance = {0, 6:C}", balance);
	}
}

// 验证代码

static void Main()
{
	IBankAccount venusAccount = new SaverAccount();
	ITransferBankAccount jupiterAccount = new CurrentAccount();
	venusAccount.PayIn(200);
	jupiterAccount.PayIn(500);
	jupiterAccount.TransferTo(venusAccount, 100);
	Console.WriteLine(venusAccount.ToString());
	Console.WriteLine(jupiterAccount.ToString());
}

你可能感兴趣的:(C#,c#,java,前端)