C#---23:Virtual、abstract、Interface的区别 & 混合使用的案例

1. virtual & abstract & interface 的区别


(1)virtual 修饰的方法
  • virtual 关键字用于声明一个方法可以被其派生类重写(override)。如果一个基类中的方法被标记为 virtual,那么任何继承这个基类的派生类都可以选择覆盖(override)这个方法,提供不同的实现。
  • 如果派生类没有显式地覆盖 virtual 方法,那么默认行为就是调用基类中的实现。
  • virtual 方法必须有具体的实现,也就是说,你不能在声明 virtual 方法时省略方法体。

(2)abstract修饰的方法
  • abstract 关键字用于声明一个类或方法是抽象的。抽象类不能被实例化,只能作为其他类的基类。
  • 抽象方法只声明而不包含任何实现,它必须在派生类中被重写。
  • abstract 方法所在的类也必须被声明为 abstract。
  • 派生类可以选择性地覆盖 abstract 类中的非抽象方法,但是所有抽象方法都必须被实现,除非派生类本身也被声明为 abstract。

(3)interface修饰的方法
  • interface 定义了一组方法、属性、事件和索引器的签名,但不包含任何实现细节。它们可以被多个类实现,从而允许这些类之间进行多态操作。
  • 实现接口的类必须提供接口中声明的所有成员的具体实现。
  • 接口可以被多个类实现,因此提供了多重继承的能力,因为 C# 不支持多重类继承。

总结:
virtual 提供了可选的重写能力,abstract 强制派生类必须实现某些功能,而 interface 则定义了一个完全由实现者填充的合同。


2. 一个class继承多个interface 的应用


step1: 创建2个接口文件
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


step2: 创建1个普通的class类文件:继承了2个interface
在这里插入图片描述


step3:实例化的tank 可以调用2个接口的方法

在这里插入图片描述


step4:最终效果:
在这里插入图片描述


step5:将实例tank赋值给不同的interface:将tank不同类型的功能进一步区分
在这里插入图片描述

step6:最终可以实现的类似下图的右半部分:
在这里插入图片描述


3. 一个class继承一个class和多个interface

如果Tank这个类还想继续扩展,需要添加一些tank自身属性的内容,就需要再多一些继承了


step1: 新建Myobjct类,设置属性的初始值:
在这里插入图片描述

step2: 初始化值的tank的时候,可以为tank赋值:
在这里插入图片描述


4. abstract作为中间介质(将不同的人以及不同的坦克关联到一起)


在这里插入图片描述

step1:新建项目TankProject,并新建Driver与Gunner类:

Driver 类仅仅负责driver相关的内容,具体是开什么车他都会开,就将IRunable对象传递进来即可(实例化的IRunable对象会定义具体的方法)

在这里插入图片描述

在这里插入图片描述


step2:Tank.cs文件的具体内容:


namespace Helloworld.AbstractStudy
{
	// Tank 类仅做为abstract类,不具体定义,只负责定义哪些方法是必须要重写的
	internal abstract class Tank : IFireable, IRunable
	{
		abstract public void Fire();

		abstract public void FireAll();

		abstract public void Run();
	}


	// 继承了Tank类,但因为Tank继承了2个interface,所以需要将这2个interface的所有方法重写一遍
	class SuperTank: Tank
	{
		override public void Fire()
		{
			Console.WriteLine("SuperTank fire");
		}

		override public void FireAll()
		{
			Console.WriteLine("SuperTank fire all");
		}

		override public void Run()
		{
			Console.WriteLine("SuperTank run ...");
		}
	}


	class HeavyTank : Tank
	{
		override public void Fire()
		{
			Console.WriteLine("HeavyTank fire");
		}

		override public void FireAll()
		{
			Console.WriteLine("HeavyTank fire all");
		}

		override public void Run()
		{
			Console.WriteLine("HeavyTank run ...");
		}
	}

}



step3:Program.cs文件的具体内容:

/*
 角色:
	1.Driver :IRunnable
	2.Gunner :IFireable
	3.Tank :
			3.1 IFireable
			3.2 IRunnable
	(SuperTank + HeavyTank ) 
 */


using Helloworld.AbstractStudy;

namespace TankProject
{
	class Progress
	{
		static void Main(string[] args)
		{
			Console.WriteLine("Hello, Welcome to my Tank Game!");

			SuperTank st = new SuperTank();

			//HeavyTank ht = new HeavyTank();

			Driver driver = new Driver(st);

			Gunner gunner = new Gunner(st);

			gunner.Fire();
			gunner.FireAll();

			driver.Drive();

		}
	}
}


step4:最终显示效果:
在这里插入图片描述


5. set & get方法的使用

(1)class中的set方法的使用
  • set 方法通常出现在属性(property)的定义中。属性提供了一种封装数据成员的方式,使代码更加清晰和易于维护。
  • set 方法允许外部代码修改属性所代表的数据成员,而 get 方法则允许读取该数据成员的值。
public class Person
{
    private string _name; // 私有字段,存储名字

    // 定义一个名为 Name 的属性
    public string Name
    {
        get { return _name; } // 返回名字
        set { _name = value; } // 设置名字,value 是传递给 set 方法的参数
    }
}

// 使用示例
class Program
{
    static void Main(string[] args)
    {
        Person person = new Person();
        
        // 调用 set 方法设置 Name 属性
        person.Name = "John Doe";
        
        // 调用 get 方法获取 Name 属性
        Console.WriteLine(person.Name); // 输出: John Doe
    }
}



(2)set & get 方法一起使用

namespace TankProject
{
	internal class MainClass
	{

		static void Main(string[] args) {

			Person person = new Person("alien");

			Console.WriteLine(person.Name); // 输出: alien

			// 调用 set 方法设置 Name 属性
			person.Name = "Alien";

			// 调用 get 方法获取 Name 属性
			Console.WriteLine(person.Name); // 输出: Alien

		}


		public class Person
		{
			private string _name; // 私有字段,存储名字

			public Person(string name)
			{
				_name = name;
			}

			// 定义一个名为 Name 的属性
			public string Name
			{
				get { return _name; } // 返回名字
				set { _name = value; } // 设置名字,value 是传递给 set 方法的参数
			}
		}

	}
}


在这里插入图片描述

在这里插入图片描述


6. gunner & driver 作为两个消费者,如何消费只有单一功能(IFireable or IRunable的对象)


step1:创建2个新的类:Car & Rocket , 分别只继承IRunable、IFireable:

在这里插入图片描述

在这里插入图片描述


step2:为Driver & Rocket两个类分别设置set方法,方便修改传递进来的实例属性:
在这里插入图片描述

在这里插入图片描述


step3:为Driver & Rocket两个类分别设置set方法,方便修改传递进来的实例属性:

在这里插入图片描述

在这里插入图片描述

相关推荐

  1. C# 接口使用案例

    2024-07-22 11:58:03       59 阅读
  2. C/C++混合编程:事半功倍利器

    2024-07-22 11:58:03       51 阅读
  3. c++中缓冲器使用案例

    2024-07-22 11:58:03       39 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-22 11:58:03       52 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-22 11:58:03       54 阅读
  3. 在Django里面运行非项目文件

    2024-07-22 11:58:03       45 阅读
  4. Python语言-面向对象

    2024-07-22 11:58:03       55 阅读

热门阅读

  1. OMOST 作画能力的硬核解析[C#]

    2024-07-22 11:58:03       15 阅读
  2. Linux 驱动学习笔记

    2024-07-22 11:58:03       14 阅读
  3. 掌握Git:面试中常见的问题与解答

    2024-07-22 11:58:03       16 阅读
  4. DOS常用命令大全

    2024-07-22 11:58:03       12 阅读
  5. 设计模式在FileBrowser中的几个应用

    2024-07-22 11:58:03       13 阅读