Files
My-Notes/笔记/CSharp/核心/抽象类和抽象方法.md
2026-06-21 09:51:55 +08:00

10 KiB

概念: 使用 abstract 关键字修饰的类,叫做==抽象类== 使用 abstract 关键字修饰的方法,叫做==抽象方法==

简单理解: 抽象类像一份“不完整的父类模板” 它可以规定子类必须有什么能力,但具体怎么做,交给子类自己实现

补充: 有些教程会把“抽象方法”叫作“抽象函数”,初学阶段可以先理解成同一个意思

通常用法:

  1. 多个类有共同身份,但父类本身不应该被直接创建对象
  2. 父类能提供一部分公共代码
  3. 父类还想强制子类必须实现某些方法
  4. 配合继承多态vob,让调用方通过父类统一调用子类行为

语法

抽象类:

abstract class 类名
{

}

抽象方法:

abstract class 类名
{
	public abstract void 方法名();
}

子类实现抽象方法:

class 子类名 : 抽象类名
{
	public override void 方法名()
	{

	}
}

注意: 抽象方法没有方法体,结尾直接写分号 ;


基础案例

abstract class Animal
{
	public string Name;

	public Animal(string name)
	{
		Name = name;
	}

	public void Eat()
	{
		Console.WriteLine(Name + "正在吃东西");
	}

	public abstract void Speak();
}

class Dog : Animal
{
	public Dog(string name) : base(name)
	{
	}

	public override void Speak()
	{
		Console.WriteLine(Name + ":汪汪");
	}
}

class Cat : Animal
{
	public Cat(string name) : base(name)
	{
	}

	public override void Speak()
	{
		Console.WriteLine(Name + ":喵喵");
	}
}

Animal a1 = new Dog("旺财");
Animal a2 = new Cat("小花");

a1.Eat();
a1.Speak();

a2.Eat();
a2.Speak();

理解:

  1. Animal 是抽象类,不能直接 new Animal()
  2. Eat() 是普通方法,子类可以直接继承使用
  3. Speak() 是抽象方法,父类只规定“动物要会叫”
  4. DogCat 必须用 override 实现自己的 Speak()
  5. Animal a1 = new Dog() 可以配合多态使用

抽象类不能直接实例化

错误写法:

abstract class Animal
{
	public abstract void Speak();
}

Animal animal = new Animal();

原因: 抽象类是不完整的类型,里面可能有没实现的抽象成员 所以不能直接创建对象

正确用法:

Animal animal = new Dog("旺财");
animal.Speak();

抽象方法必须在子类中实现

如果子类不是抽象类,就必须实现父类中所有抽象方法。

abstract class Shape
{
	public abstract double GetArea();
}

class Circle : Shape
{
	public double Radius;

	public Circle(double radius)
	{
		Radius = radius;
	}

	public override double GetArea()
	{
		return 3.14 * Radius * Radius;
	}
}

错误写法:

class Circle : Shape
{

}

原因: Circle 是普通类,但没有实现 Shape 要求的 GetArea()


子类也可以继续抽象

如果子类暂时不想实现所有抽象方法,那么这个子类也必须声明成 abstract

abstract class Shape
{
	public abstract double GetArea();
	public abstract double GetLength();
}

abstract class RoundShape : Shape
{
	public override double GetLength()
	{
		return 0;
	}

	// GetArea 暂时不实现,所以 RoundShape 也必须是抽象类
}

理解: 普通类必须把抽象成员补完整 抽象类可以继续把没补完的内容留给下一级子类


抽象类里可以有什么

抽象类不只是能写抽象方法,也可以写普通成员。

abstract class Character
{
	public string Name;
	public int Hp;

	public Character(string name, int hp)
	{
		Name = name;
		Hp = hp;
	}

	public void TakeDamage(int damage)
	{
		Hp -= damage;
		Console.WriteLine(Name + "受到了" + damage + "点伤害");
	}

	public virtual void Move()
	{
		Console.WriteLine(Name + "正在移动");
	}

	public abstract void Attack();
}

抽象类中可以有:

  1. 成员变量
  2. 成员属性
  3. 构造函数
  4. 普通方法
  5. 虚方法
  6. 抽象方法
  7. 抽象属性、抽象索引器、抽象事件

一句话: 抽象类可以有“已经写好的公共功能”,也可以有“要求子类必须补上的功能”


抽象类可以有构造函数

抽象类不能直接 new,但它仍然可以有构造函数。

原因: 创建子类对象时,会先构造父类那一部分

abstract class Enemy
{
	public string Name;

	public Enemy(string name)
	{
		Name = name;
		Console.WriteLine("Enemy构造");
	}

	public abstract void Attack();
}

class Boss : Enemy
{
	public Boss(string name) : base(name)
	{
		Console.WriteLine("Boss构造");
	}

	public override void Attack()
	{
		Console.WriteLine(Name + "发动攻击");
	}
}

Boss boss = new Boss("魔王");

执行顺序还是:

  1. 先执行父类 Enemy 构造函数
  2. 再执行子类 Boss 构造函数

abstract、virtual、override 的关系

abstract 方法:

public abstract void Attack();

特点:

  1. 没有方法体
  2. 子类必须实现
  3. 本身就表示允许被重写,所以子类用 override

virtual 方法:

public virtual void Move()
{
	Console.WriteLine("默认移动");
}

特点:

  1. 有方法体
  2. 子类可以选择重写,也可以不重写
  3. 子类重写时也用 override

对比:

  1. abstract:父类不给默认实现,子类必须改
  2. virtual:父类给默认实现,子类可以改
  3. override:子类真正改写父类的抽象方法或虚方法

抽象方法和普通方法的区别

普通方法:

public void Eat()
{
	Console.WriteLine("吃东西");
}

抽象方法:

public abstract void Speak();

区别:

  1. 普通方法有方法体,抽象方法没有方法体
  2. 普通方法可以直接继承使用,抽象方法必须由子类实现
  3. 普通方法可以写在普通类或抽象类里,抽象方法只能写在抽象类里
  4. 抽象方法天然就是给多态准备的

抽象属性

抽象的不一定只有方法,也可以是属性。

abstract class Weapon
{
	public abstract int Damage { get; }
}

class Sword : Weapon
{
	public override int Damage
	{
		get
		{
			return 10;
		}
	}
}

简写:

class Bow : Weapon
{
	public override int Damage => 8;
}

理解: 父类规定“武器必须有伤害值” 不同武器自己决定伤害值是多少


抽象类和密封类不能同时用

错误写法:

sealed abstract class Animal
{

}

原因:

  1. abstract 表示这个类必须被继承后才能补完整
  2. sealed 表示这个类不能被继承
  3. 两个要求互相矛盾

这个点可以和密封类一起记。


常见错误

错误1:抽象方法写了方法体

abstract class Animal
{
	public abstract void Speak()
	{
		Console.WriteLine("动物叫");
	}
}

抽象方法不能有方法体。


错误2:普通类里写抽象方法

class Animal
{
	public abstract void Speak();
}

抽象方法只能写在抽象类中。


错误3:子类没实现抽象方法

abstract class Animal
{
	public abstract void Speak();
}

class Dog : Animal
{

}

Dog 如果是普通类,就必须 override Speak()


错误4:抽象方法上再写 virtual

abstract class Animal
{
	public abstract virtual void Speak();
}

抽象方法本身就表示必须被重写,不需要再写 virtual


错误5:直接 new 抽象类

Animal animal = new Animal();

抽象类不能直接实例化。


什么时候用抽象类

适合用抽象类的情况:

  1. 多个子类确实属于同一种父类
  2. 父类有公共字段、属性、构造函数或普通方法可以复用
  3. 父类还需要强制子类实现某些行为
  4. 你希望调用方通过父类统一调用子类对象

例如:

  • Animal:动物都能吃,但不同动物叫声不同
  • Shape:图形都有面积,但不同图形面积算法不同
  • Character:角色都有血量,但不同角色攻击方式不同

不适合用抽象类的情况:

  1. 只是想规定一种能力,例如“能飞”“能攻击”
  2. 多个类之间没有明确的父子关系
  3. 一个类需要同时拥有多种能力

这些情况后面通常更适合用接口


和多态的关系

抽象类经常和多态一起使用。

abstract class Skill
{
	public abstract void Release();
}

class FireSkill : Skill
{
	public override void Release()
	{
		Console.WriteLine("释放火球");
	}
}

class IceSkill : Skill
{
	public override void Release()
	{
		Console.WriteLine("释放冰锥");
	}
}

void UseSkill(Skill skill)
{
	skill.Release();
}

UseSkill(new FireSkill());
UseSkill(new IceSkill());

理解:

  1. Skill 规定所有技能都必须能 Release()
  2. FireSkillIceSkill 各自实现释放逻辑
  3. UseSkill 只依赖抽象父类,不依赖具体技能类

这就是: ==抽象类定规则,多态负责运行时执行不同实现==


注意

  1. 抽象类不能直接创建对象
  2. 抽象方法没有方法体,结尾用分号
  3. 有抽象方法的类必须是抽象类
  4. 普通子类继承抽象类后,必须实现所有抽象成员
  5. 抽象类可以有普通方法、字段、属性和构造函数
  6. 抽象方法不能写 private,因为子类需要能重写它
  7. 抽象方法不能同时写 virtual,因为它本身就是虚的
  8. 抽象类不能和 sealed 同时使用

一句话记忆

==抽象类不能直接 new,抽象方法只定规则不写实现,子类必须 override。==

再压缩一点: ==父类抽象定规矩,子类重写补细节。==


面试/复习时怎么说

可以这样答:

“抽象类是用 abstract 修饰的类,不能直接实例化,主要用来作为父类。
它可以包含普通成员,也可以包含抽象成员。抽象方法没有方法体,只声明方法签名,普通子类继承后必须用 override 实现。
抽象类适合用来提取多个子类的共同代码,同时强制子类实现不同的行为,常和继承、多态一起使用。”


引用:

  1. Microsoft Learn: abstract (C# Reference)
  2. Microsoft Learn: Abstract and Sealed Classes and Class Members
  3. Microsoft Learn: Inheritance - derive types to create more specialized behavior

#抽象类 #抽象方法 #核心