C# Interface、Abstract与Virtual用法详解及区别对比
在C#面向对象编程中,理清接口(Interface)、抽象(Abstract)与虚方法(Virtual)的关系是掌握多态性的关键。本文结合代码实例,深入解析三者的定义规则、实现要求以及在派生类中的行为差异。
一、 Interface:纯契约声明
interface主要用于定义一组行为规范(契约),不包含任何实现细节。其核心特点包括:
- 仅定义规约:只提供方法签名,严禁提供方法主体。
- 默认公开且无修饰符:接口成员自动默认为
public,因此不能显式添加public、abstract等访问修饰符。 - 严格限制属性:接口内不能包含字段变量(Field)或构造函数。否则编译器将报错。
public interface IPerson
{
void getName(); // 正确:不包含方法主体
void getAge(string s); // 正确:可包含参数
// IPerson(); // 错误:接口不能有构造函数
// string name; // 错误:接口不能有字段变量
// public void getIDcard(); // 错误:接口不需要public修饰符
}第1步:通过继承关系实现接口
类可以通过冒号 : 实现接口。实现类必须强制性地为接口中的所有方法提供具体实现逻辑,这与继承普通类的格式保持一致。
public class Chinese : IPerson
{
public Chinese() { /* 构造 */ }
public void getName() { /* 实现getName */ }
public void getAge(string s) { /* 实现getAge */ }
}二、 Abstract:抽象类与方法
abstract既可以修饰类也可以修饰方法。它提供了一种介于纯粹接口和完整实现之间的形态。
- 抽象类约束:包含抽象方法的类必须是抽象类;抽象类无法直接实例化,必须由子类继承并实现抽象方法。
- 抽象方法特征:仅声明无主体,必须在派生类中用
override关键字强制执行实现。
第2步:构建含抽象与虚方法的基类
在基类中同时定义抽象方法和虚方法(virtual),以此作为后续测试多态行为的样本。
public abstract class Book
{
public Book() { } // 可以包含普通构造函数
public abstract void getPrice(); // 抽象方法:无主体,必须Override
public virtual void getName()
{
Console.WriteLine("this is a test: virtual getName()");
} // 虚方法:有主体,允许Override
public virtual void getContent()
{
Console.WriteLine("this is a test: virtual getContent()");
} // 虚方法:有主体,允许Override
public void getDate() // 一般方法:若无virtual标记,需使用new隐藏
{
Console.WriteLine("this is a test: void getDate()");
}
}
public class JavaBook : Book
{
// 实现抽象方法(必须)
public override void getPrice()
{
Console.WriteLine("JavaBook override abstract getPrice()");
}
// 覆盖虚方法(非必须)
public override void getName()
{
Console.WriteLine("JavaBook override virtual getName()");
}
}三、 Virtual:虚方法与动态绑定
标记为 virtual 的方法允许派生类进行重写(Override)。如果派生类未选择重写,则默认调用基类版本。这与抽象方法(Abstract)有本质区别:抽象类不提供默认主体,而虚类提供默认主体且重写是可选的。
第3步:测试 Override 的多态表现
观察当对象声明为基类类型时,是否仍能调用派生类的重写方法。
public class test
{
public static void Main()
{
JavaBook jbook = new JavaBook();
jbook.getPrice(); // 输出:JavaBook中重写内容
jbook.getName(); // 输出:JavaBook中重写内容
jbook.getContent(); // 输出:Book中默认内容(因JavaBook未重写此虚方法)
jbook.getDate(); // 输出:Book中默认内容(无virtual标记,静态绑定)
}
}四、 Abstract 与 Virtual 的核心区别总结
两者在派生类重写时都使用 override 关键字,但在设计意图上截然不同:
- Abstract 代表一种“强制”。它是骨架的一部分,要求子类必须填补空白。
- Virtual 代表一种“扩展”。它提供了基础功能,允许子类在不破坏原有调用的前提下增强或改变行为。
验证 Abstract 强制实现
如果尝试移除 override 关键字来编译 Abstract 方法,程序将无法通过编译。
public abstract class Book
{
// 抽象方法,不含主体
public abstract void Introduce();
}
public class JavaBook : Book
{
// 必须强制添加 override 关键字,否则编译错误
public override void Introduce()
{
Console.WriteLine("I'm Java");
}
}
// ... 测试代码
Book book = new JavaBook();
book.Introduce(); // 此时动态绑定成功,调用子类的 Introduce()。五、 New:显式隐藏而非重写
如果一个基类的方法既不是 abstract 也不是 virtual,而在派生类中使用了同名同参的方法,这种行为被称为“隐藏”(Hiding),必须使用 new 关键字明确标示(即便不加也会隐式编译警告)。
第4步:体验 Static Binding (静态绑定)
使用 new 关键字隐藏父类方法时,运行结果取决于对象的声明类型,而不是实际创建的对象类型。
public abstract class Book
{
public void SayHi() { Console.WriteLine("Hi, I'm book"); }
}
public class JavaBook : Book
{
// 使用 new 显式隐藏父类方法,消除编译警告
public new void SayHi() { Console.WriteLine("Hi, I'm Java"); }
}
public class test
{
public static void Main()
{
JavaBook javaBook = new JavaBook();
javaBook.SayHi(); // 调用 JavaBook.SayHi () (对象类型判定)
Book book = new JavaBook(); // 声明为基类
book.SayHi(); // 调用 Book.SayHi() (声明类型判定)
}
}以上就是对C#中Interface、Abstract与Virtual的详细解析及多态性对比,更多关于C#面向对象高级特性的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









