什么是抽象类
C# abstract修饰符表示所修饰的事物的实现缺少或不完整。使用该关键字能修饰类和方法,修饰的方法被称为抽象方法、修饰的类被称为抽象类。
在 C# 语言中抽象方法是一种不带方法体的方法,仅包含方法的定义,语法形式如下。
访问修饰符 abstract 方法返回值类型 方法名(参数列表);
在定义抽象类时,若使用 abstract 修饰类,将其放到 class 关键字的前面,语法形式如下。
访问修饰符 abstract class 类名
{
//类成员
}
抽象类具有以下功能:
●抽象类无法实例化。
●抽象类可以包含抽象方法和访问器。
●由于两个修饰符的含义相反,因此无法使用密封的(C#Reference)修饰符来修改抽象类。Sealed修饰符可防止类被继承,而abstract修饰符则需要继承一个类。
●抽象方法必须定义在抽象类中,抽象类也可以定义非抽象方法。
●因为抽象方法声明不提供任何实际实现,所以没有方法主体;方法声明仅以分号结尾,并且签名后没有花括号({})。
例如:
public abstract void MyMethod();
【实例 1】创建抽象类 ExamResult,并在类中定义数学 (Math)、英语 (English) 成绩的属性,定义抽象方法计算总成绩。
//abstract 抽象
//1.覆盖父类,让子类重新定义。
//2.抽象方法 子类必须实现
//3.抽象类 不能被实例化,只能被继承。生成抽象方法,子类必须实现。
//4.抽象方法必须定义在抽象类中,抽象类也可以定义非抽象方法。
/// <summary>
/// 【实例 1】创建抽象类 ExamResult,并在类中定义数学 (Math)、英语 (English) 成绩的属性,定义抽象方法计算总成绩。
/// </summary>
abstract class ExamResult
{
//学号
public int Id { get; set; }
//数学成绩
public double Math { get; set; }
//英语成绩
public double English { get; set; }
//计算总成绩
public abstract void Say();
}
class Math : ExamResult
{
public override void Say()
{
double count = (Math + English) / 2;
Console.WriteLine("学号" + Id + ",平均成绩为:" + count);
}
public void MathSay()
{
Console.WriteLine("我喜欢数学课,因为数学课可以提高我的算法。");
}
}
class Englisth : ExamResult
{
public override void Say()
{
double count = (Math + English) / 2;
Console.WriteLine("学号" + Id + ",平均成绩为:" + count);
}
}
static void Main(string[] args)
{
Math m = new Math();
m.Id = 666;
m.Math = 30;
m.English = 60;
m.Say();
Englisth e = new Englisth();
e.Id = 555;
e.Math = 35;
e.English = 65;
e.Say();
C# virtual关键字详解
virtual 关键字能修饰方法、属性、索引器以及事件等,用到父类的成员中。
使用 virtual 关键字修饰属性和方法的语法形式如下。
//修饰属性
public virtual 数据类型 属性名{get; set;}
//修饰方法
访问修饰符 virtual 返回值类型方法名
{
语句块;
}
●子类继承父类后能重写父类中的成员,重写的关键字是 override。
在子类中重写该方法的代码如下。
public override 返回值类型 方法名()
{
语句块;
}
virtual 关键字特点
●virtual 关键字不能修饰使用 static 修饰的成员。
●virtual关键字不能与 static、abstract、private 或 override 修饰符一起使用 。
【实例 二】创建学生类 Student。继承Person,并且说出他们的情况
//这个是Virtual关键字的总结
//1.重写父类,覆盖父类,让子类重新定义。
//2.父类生成虚拟类,子类可以实现,也可以不实现。
//3.Virtual关键字不可以和static private delegate 方法一起使用。
class Person
{
public String Name { get; set; }
public Person(string name)
{
this.Name = name;
}
public int Age { get; set; }
public double Weight { get; set; }
public virtual void Say()
{
Console.WriteLine("我是" + Name + ",我今年" + Age + ",我的体重" + Weight + ",我不仅仅会唱歌还会跳舞。");
}
public virtual void Hello()
{
Console.WriteLine("Hello");
}
}
class Student : Person
{
public string School { get; set; }
public int Scorce { get; set; }
public Student(string name, string school) : base(name)
{
this.Name = name;
this.School = school;
}
public override void Say()
{
Console.WriteLine("我的学校是" + School + ",我今年" + Age + ",我今年的期末考试成绩:" + Scorce);
}
}
static void Main(string[] args)
{
Student st = new Student("张三", "深圳大学");
Person pr = new Person("王五");
pr.Age = 30;
pr.Weight = 60;
pr.Say();
pr.Hello();
st.Age = 20;
st.Scorce = 120;
st.Say();
C#接口详解
在日常生活中,手机、笔记本电脑、平板电脑等电子产品提供了不同类型的接口用于充电或者连接不同的设备。
不同类型接口的标准不一样,例如电压、尺寸等。
在C#语言中,接口也会定义一种标准,如果需要使用接口,必须满足接口中所定义的内容。
在C#语言中,类之间的继承关系仅支持单重继承,而接口是为了实现多重继承关系设计的。
一个类能同时实现多个接口,还能在实现接口的同时再继承其他类,并且接口之间也可以继承。
接口定义的语法形式如下。
interface 接口名称
{
接口成员;
}
1) 接口名称
通常是以 I 开头,再加上其他的单词构成。例如创建一个计算的接口,可以命名为 ICompute。
2) 接口成员
接口中定义的成员与类中定义的成员类似。
接口中定义的成员必须满足以下要求。
●接口中的成员不允许使用 public、private、protected、internal 访问修饰符。
●接口中的成员不允许使用 static、virtual、abstract、sealed 修饰符。
●在接口中不能定义字段。
●在接口中定义的方法不能包含方法体。
接口的实现实际上和类之间的继承是一样的,也是重写了接口中的方法,让其有了具体的实现内容。
但需要注意的是,在类中实现一个接口时必须将接口中的所有成员都实现,否则该类必须声明为抽象类,并将接口中未实现的成员以抽象方式实现。
在 C# 语言中实现接口的具体语法形式如下。
class 类名 : 接口名
{
//类中的成员以及实现接口中的成员
}
以抽象方式实现接口中的成员是指将接口中未实现的成员定义为抽象成员,示例代码如下
interface ITest
{
string name { get; set}
void Print();
}
abstract class Test : ITest
{
public abstract string name { get; set; }
public abstract void Print();
}
从上面的代码可以看出,在实现类 Test 中将未实现的属性和方法分别定义为抽象属性和抽象方法,并将实现类定义为抽象类。
在实现接口的成员时有两种方式,一种是隐式实现接口成员,一种是显式实现接口成员。
显式实现接口是指在实现接口时所实现的成员名称前含有接口名称作为前缀。
接下来将通过实例来演示在编程中隐式实现接口与显式实现接口有什么区别。
根据题目要求,首先使用隐式方式来实现接口 ICompute 的成员,以计算机专业的学生类 (ComputerMajor) 实现 ICompute 接口,为其添加英语 (English)、编程 (Programming)、数据库 (Database) 学科成绩属性,代码如下。
class ComputerMajor : ICompute
{
public int Id { get; set; } //隐式的实现接口中的属性
public string Name { get; set; } //隐式实现接口中的属性
public double English { get; set; }
public double Programming { get; set; }
public double Database { get; set; }
public void Avg() //隐式实现接口中的方法
{
double avg = (English + Programming + Database) / 3;
Console.WriteLine("平均分:" + avg);
}
public void Total()
{
double sum = English + Programming + Database;
Console.WriteLine("总分为:" + sum);
}
}
class Program
{
static void Main(string[] args)
{
ComputerMajor computerMajor = new ComputerMajor();
computerMajor.Id = 1;
computerMajor.Name = "李明";
computerMajor.English = 80;
computerMajor.Programming = 90;
computerMajor.Database = 85;
Console.WriteLine("学号:" + computerMajor.Id);
Console.WriteLine("姓名:" + computerMajor.Name);
Console.WriteLine("成绩信息如下:");
computerMajor.Total();
computerMajor.Avg();
}
}
class ComputerMajor : ICompute
{
public double English { get; set; }
public double Programming { get; set; }
public double Database { get; set; }
int ICompute.Id { get; set; } //显示实现接口中的属性
string ICompute.Name { get; set; } //显示实现接口中的属性
void ICompute.Total() //显示实现接口中的方法
{
double sum = English + Programming + Database;
Console.WriteLine("总分数:" + sum);
}
void ICompute.Avg()
{
double avg = (English + Programming + Database) / 3;
Console.WriteLine("平均分为:" + avg);
}
}
//接口方法的实现
ComputerMajor computerMajor = new ComputerMajor();
ICompute compute = computerMajor; //创建接口的实例
compute.Id = 1;
compute.Name = "李明";
computerMajor.English = 80;
computerMajor.Programming = 90;
computerMajor.Database = 85;
Console.WriteLine("学号:" + compute.Id);
Console.WriteLine("姓名:" + compute.Name);
Console.WriteLine("成绩信息如下:");
compute.Total();
compute.Avg();
执行上面的代码,效果与上图一致。从调用的代码可以看出,在调用显式方式实现接口的成员时,必须使用接口的实例来调用,而不能使用实现类的实例来调用。
与类之间的继承类似,实现类的实例也可以隐式转换为其所实现接口的接口类型。
C#接口中多态的实现
在前面学过多态能使用类之间的继承关系来实现,通过多个类继承同一个接口,并实现接口中的成员也能完成多态的表示。
使用接口实现多态 需要满足以下两个条件。
定义接口并使用类实现了接口中的成员。
创建接口的实例指向不同的实现类对象。
假设接口名称为 IProgram ,分别定义两个实现类来实现接口的成员,示例代码如下。
从上面的执行效果可以看出,使用不同类实现同一接口的方法输出的内容各不相同,这就是使用接口的方式实现多态的方法。