精通C#学习笔记---继承和多态

#继承的基本机制
代码重用归为两类:继承(is-a),包含/委托(has-a)
继承保护了封装。

##is-a
C#要求一个类只能有一个直接基类。
sealed关键字:
如果我们将类标记为sealed,编译器将不会允许我们从这个类型派生。
C#结构总是隐式密封的。
如果对基类的虚函数【vritual/override修饰的】用sealed修饰,则,在此基类的派生类中,此虚函数不可以被override【即不允许派生类定义自己版本的实现】。

只要子类想访问由父类定义的公共或受保护的成员,就可以使用base关键字。

class A
{
	public A(int a)
	{...}
}
class B : A
{
	public B(int a, int b)
		:base(a)
	{}
}

private类型成员,只能在所属类内部实现中使用。
protected类型成员,可以在所属类和其派生类内部实现从使用。
public类型成员,可以在所属类和其派生类内部实现被使用,也可被类或其派生类对象通过点操作符访问。

##has-a
包含/委托编程

class BenefitPackage
{
	public double ComputePayDeduction()
	{
		return 125.0;
	}
}

class Employee
{
	protected BenefitPackage empBenefits = new BenefitPackage();
}

如果要公开被包含对象的功能给外部世界,需要委托。
委托就是增加公共成员到包含类,以便使用被包含对象的功能。

嵌套类型:直接在类或结构作用域中定义类型【枚举,类,接口,结构或委托】。
被嵌套类型被认为是嵌套类的成员。可以像操作其它成员【字段,属性,方法,事件等】操作被嵌套类型。

public class OuterClass
{
	public class PublicInnerClass{}
	private class PrivateInnerClass{}
}

class Main
{
	static void Main()
	{
		OuterClass.PublicInnerClass inner = new OuterClass.PublicInnerClass();
	}
}

嵌套类型特征:
类型可用private修饰。
嵌套类型可以访问包含类的所有成员
嵌套类一般用作外部类的辅助设施。

#多态
1.
多态为子类提供了一种方式,使其可以定义由基类定义的方法。
vritual用于修饰基类的虚方法
override用于修饰派生类重写的基类的虚方法

class Employee
{
	public virtual void GiveBonus(float amount)
	{
		Pay += amount;
	}
	...
}

class SalesPerson : Employee
{
	public override void GiveBonus(float amount)// 
	{
		base.GiveBouns(amount);
		...
	}
}

2.抽象基类
可以用abstract修饰类。不允许创建被abstract修饰类的对象。
抽象基类,可以定义抽象成员。
抽象成员:基类不提供默认实现,必须在派生类中提供实现。

abstract class Shape
{
	public Shape(string name = "NoName")
	{
		PetName = name;
	}
	
	public string PetName{get; set;};
	public virtual void Draw()
	{
		Console.WriteLine("Inside Shape.Draw()");
	}
}

class Circle : Shape
{
	public Circle(){}
	public Circle(string name)
		: base(name)
	{}
}

class Hexagon : Shape
{
	public Hexagon(){}
	public Hexagon(string name)
		: base(name)
	{}
	public override void Draw()
	{
		Console.WriteLine("Drawing {0} the Hexagon", PetName);
	}
}

只能在抽象基类中定义抽象成员

abstract class Shape
{
	public Shape(string name = "NoName")
	{
		PetName = name;
	}
	
	public string PetName{get; set;};
	// 抽象方法不提供实现
	public abstract void Draw();
}

如果基类中存在抽象方法,派生类要么对基类的抽象方法均进行override来提供具体实现。否则,派生类也将成为抽象类,且派生类需要用abstract修饰。

3.成员遮蔽
如果派生类定义的成员和定义在基类中的成员一致,派生类就遮蔽了父类的版本。

class Circle
{
	public void Draw()
	{}

	public virtual void Draw(int num)
	{...}
}
class ThreeDCircle : Circle
{
	// 在此类内部,此类实例或此类的名字通过点操作符,此类的派生类内部,此类派生类实例或此类派生类的名字通过点操作符 访问Draw时,访问的将是此类的Draw。要访问此类基类的Draw,需要将类型转换为基类再访问。
	// 编译时,会有警告。通过添加new修饰符可消除警告。
	// 对成员字段同样适用。
	public [new] void Draw()
	{
		...
	}

	public override void Draw(int num)
	{...}
}

class Main
{
	static void Main()
	{
		ThreeDCricle o = new ThreeDCircle();
		// 执行ThreeDCricle::draw
		// 点操作符访问类成员,若成员不是虚成员,依据左边类型静态类型,决定名字查找起始作用域。
		// 若成员是虚成员,依据左边类型动态类型,决定名字查找起始作用域。
		o.draw();
		// 执行ThreeDCricle::draw
		o.draw(10);
	
		// 执行Circle::draw
		// 因为(Circle)o后,把(Circle)o整体的静态类型变成了Circle。动态类型仍然是ThreeDCricle
		((Circle)o).Draw();
		// 执行ThreeDCricle::draw
		((Circle)o).Draw(10);
	}
}

4.基类/派生类的转换规则
如果两个类通过is-a关系关联,在基类引用中保存派生类型总是安全的。
使用C#强制转换 操作符进行显式的向下转换。

5.C#的as
强制转换在运行时,如果转换失败,会收到运行时异常。
使用as,就可以通过检查null返回值来检测兼容性
// frank可以转换为Hexagon类型时,返回转换后的Hexagon类型。不能时,返回null
Hexagon hex2 = frank as Hexagon;
if(hex2 == null)

6.C#的is
如果类型不兼容,is关键字就返回false,而不是null引用

static void GivePromotion(Employee emp)
{
	if(emp is Manager)
	{
		((Manager)emp).xxx
	}
}

7.System.Object
查看.NET开源实现的地址:
https://referencesource.microsoft.com/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

raindayinrain

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值