参考书:《 visual C# 从入门到精通》
第二部分 理解C#对象模型
第12 章 使用继承
文章目录
12.1 什么是继承
程序设计中,继承的问题就是分类的问题,它反映了类和类的关系。
12.2 使用继承
class DerivedClass:BaseClass{
...;
}
DerivedClass
派生类将从BaseClass
基类继承,基类中的方法将成为派生类的一部分。C#中一个类最多只能从一个其他的类派生。注意不要和C++
、Java
中的继承搞混了,格式上都是有区别的。
12.2.1 复习System.Object类
System.Object
类是所有类的根,所有类都隐式派生自System.Object
类。所以对于一个类,编译器会悄悄将它重写成以下代码:
class Mannal:System.Object{
...;
}
所以定义的所有类都自动继承System.Object类的所有功能,包括ToString
方法。
12.2.2 调用基类构造器
派生类还会自动包含来自基类的所有字段。派生类的构造器在执行初始化时最好调用一下基类的构造器。可以使用base
关键字来调用基类构造器。
如:
class Mamal{
public Mamal(String name){
...;
}
...;
}
class Horse:Mamal{
public Horse(String name):base(name);{
...;
}
...;
}
如果派生类构造器中不显示调用基类构造器的话,编译器会自动插入对基类的默认构造器的调用:
class Horse:Mamal{
public Horse(String name):base(){
...;
}
}
12.2.3 类的赋值
如Mammal
、Horse
、Whale
定义如下:
class Mammal{
...;
}
class Horse:Mamal{
...;
}
class Whale:Mammal{
...;
}
Horse myHorse=new Horse(...);
Whale myWhale=myHorse;
错误,不同类型
但可以这样:Mammal myMammal=myHorse;
,合法,Mammal
是Horse
的基类。但这样是有限制的。Horse
或Whale
类定义的任何额外的方法都不能通过Mammal类来访问。
12.2.4 声明新方法
派生类定义方法时会屏蔽和基类具有相同签名的方法。这样在编译时会显示警告消息,这时可以用new
关键字来消除警告。
class Mammal{
...;
public void Talk(){
...;
}
}
class Horse:Mammal{
...;
new public void Talk(){
...;
}
}
12.2.5 声明虚方法
用virtual
关键字标记,如System.Object的ToString
方法的定义:
namsespace System{
class Object{
public virtual string ToString(){
...;
}
...;
}
...;
}
故意被设计成被重写的方法称为虚方法
12.2.6 声明重写方法
派生类用override
关键字重写基类的虚方法
class Horse:Mammal{
...;
public override string ToString(){
...;
}
}
派生类中方法的新实现可以用base
关键字调用方法的基类版本:
public override string ToString(){
base.ToString();
...;
}
使用virtual
和override
时必须遵守以下规则:
- 虚方法不能私有
- 虚方法和重写方法的签名必须完全一致
- 只能重写虚方法
- 如果派生类不用
override
声明方法,就不是重写基类方法而是隐藏方法 - 重写方法隐式地成为虚方法,可在派生类中被重写。但不允许用
virtual
将重写方法显式声明为新方法
12.2.7 理解受保护的访问
除了public
和private
,还有protented
关键字:允许基类的派生类访问而阻止其他类访问。
下面我们实际编写代码:
新建下面几个源文件:
Vehicle.cs
using System;
using System.Collections.Generic;
using System.Text;
namespace c12_2_7
{
class Vehicle
{
public void StartEngine(String noiseToMakeWhenStarting)
{
Console.WriteLine($"Starting engine:{noiseToMakeWhenStarting}");
}
public void StopEngine(string noiseToMakeWhenStopping)
{
Console.WriteLine($"Stopping engine:{noiseToMakeWhenStopping}");
}
public virtual void Drive()
{
Console.WriteLine("Default implementation of the Drive method");
}
}
}
Airplane.cs
using System;
using System.Collections.Generic;
using System.Text;
namespace c12_2_7
{
class Airplane:Vehicle
{
public void TakeOff()
{
Console.WriteLine("Wu~Hu~, Taking off");
}
public void Land()
{
Console.WriteLine("Landing");
}
public override void Drive()
{
Console.WriteLine("Flying");
}
}
}
car.cs
using System;
using System.Collections.Generic;
using System.Text;
namespace c12_2_7
{
class car:Vehicle
{
public void Accelerate()
{
Console.WriteLine("Accelerate");
}
public void Brake()
{
Console.WriteLine("Breaking");
}
public override void Drive()
{
Console.WriteLine("Motoring");
}
}
}
主程序Program.cs
using System;
namespace c12_2_7
{
class Program
{
static void dowork()
{
Console.WriteLine("Journey by airplane:");
Airplane myPlane = new Airplane();
myPlane.StartEngine("Contace");
myPlane.TakeOff();
myPlane.Drive();
myPlane.Land();
myPlane.StartEngine("Whirr");
Console.WriteLine("\nJourney by car:");
car myCar = new car();
myCar.StartEngine("Brm brm");
myCar.Accelerate();
myCar.Drive();
myCar.Brake();
myCar.StartEngine("Phut phut");
Console.WriteLine("\nTesting polymorphism");//测试多态性
Vehicle v = myCar;
v.Drive();
v = myPlane;
v.Drive();
}
static void Main(string[] args)
{
dowork();
}
}
}
运行结果:
12.3 理解扩展方法
扩展方法允许添加静态方法来扩展现有的类型。引用被扩展类型的数据可调用扩展方法。
扩展方法在静态类中定义,被扩展的类型必须式方法的第一个参数,而且必须附加this
关键字。
static class Util{
public static int Negate(this int i){
return -i;
}
}
int x=591;
Console.WriteLine($"x.Negate {x.Negate}");
下面我们新建一个控制台应用,首先添加一个新建项:
Util.cs
using System;
using System.Collections.Generic;
using System.Text;
namespace C_12_3
{
static class Util
{
public static int ConvertToBase(this int i,int baseToConvertTo)
{
if (baseToConvertTo < 2 || baseToConvertTo > 10)
{
throw new ArgumentException("Value cannot be converted to base"
+ baseToConvertTo.ToString());
}
int result = 0;
int iteration = 0;
do
{
int nextDigit = i % baseToConvertTo;
i /= baseToConvertTo;
result += nextDigit * (int)Math.Pow(10, iteration);
iteration++;
} while (i != 0);
return result;
}
}
}
Program.cs
中的代码如下:
using System;
//using C_12_3;
namespace C_12_3
{
class Program
{
static void dowork()
{
int x = 591;
for(int i = 2; i <= 10; ++i)
{
Console.WriteLine($"{x} in base {i} is{ x.ConvertToBase(i)}");
}
}
static void Main(string[] args)
{
dowork();
}
}
}
运行结果如图: