实现多态的方式——抽象类
2、抽象类
抽象类的特点:
1)、抽象类中的抽象成员必须标记为abstract,并且不能有任何实现。
方法不能有任何实现是指,方法没有大括号,也没有方法体。
只有大括号,没有方法体的方法叫做空实现。
2)、抽象成员必须标记在抽象类中
3)、抽象类是有构造函数的,但抽象类不能被实例化
4)、子类继承抽象类后,必须把父类中的所有抽象成员都重写。(除非子类也是一个抽象类,则可以不重写)
注意:在重写抽象成员的时候,必须在前面加上override标记,否则编译器会报错。用虚方法实现多态的话,也要加上override标记,但省略override,编译器不会报错。
5)、抽象成员的访问修饰符不能是private
6)、在抽象类中可以包含实例成员,并且它们可以不被子类实现
7)、如果父类的抽象方法中有参数。那么,继承这个抽象父类的子类在重写父类的方法的时候,必须传入对应的的参数。
如果抽象父类的抽象方法中有返回值,那么子类在重写这个抽象方法的时候,也必须要写上返回值。
也就是说,子类在重写抽象父类的抽象方法的时候,必须保证方法的签名与父类的方法签名一致。(方法的签名:方法的参数和返回值)
什么时候使用抽象类:在已有的几个类中,如果说我们可以抽象出一个父类,并且父类中必须写上这几个子类共有的一个方法,且不知道如何去写这个方法。
圆形和矩形都有一个共同的父类:形状,但形状却是抽象的,我们无法计算它的面积和周长,所以必须写成抽象类。而圆形和矩形,它们计算面积和周长的方法也是不同的。这样,我们就必须对形状这个抽象类中,计算面积和周长的方法进行重写。
class Program
{
static void Main(string[] args)
{
//使用多态求矩形的面积和周长以及圆形的面积和周长
Shape shape = new Square(5, 6); //new Circle(5);
double area = shape.GetArea();
double perimeter = shape.GetPerimeter();
Console.WriteLine("这个形状的面积是{0},周长是{1}", area, perimeter);
Console.ReadKey();
}
}
public abstract class Shape
{
public abstract double GetArea();
public abstract double GetPerimeter();
}
public class Circle : Shape
{
private double _r;
public double R
{
get { return _r; }
set { _r = value; }
}
public Circle(double r)
{
this.R = r;
}
public override double GetArea()
{
return Math.PI * this.R * this.R;
}
public override double GetPerimeter()
{
return 2 * Math.PI * this.R;
}
}
public class Square : Shape
{
private double _height;
public double Height
{
get { return _height; }
set { _height = value; }
}
private double _width;
public double Width
{
get { return _width; }
set { _width = value; }
}
public Square(double height, double width)
{
this.Height = height;
this.Width = width;
}
public override double GetArea()
{
return this.Height * this.Width;
}
public override double GetPerimeter()
{
return (this.Height + this.Width) * 2;
}
}
抽象类也可以包含抽象的属性,因为属性的本质是 get、set这两个方法。
class Program
{
static void Main(string[] args)
{
//狗狗会叫 猫咪会叫
Animal a = new Cat();//new Dog();
a.Bark();
Console.ReadKey();
}
}
public abstract class Animal
{
public Animal(int age)
{
this.Age = age;
}
public virtual void T()
{
Console.WriteLine("动物有声明");
}
private int _age;
public int Age
{
get { return _age; }
set { _age = value; }
}
//Bark()没有任何实现
public abstract void Bark();
public abstract string Name
{
get;
set;
}
//Test()只有大括号,没有方法体,是空实现
public void Test()
{
//空实现
}
}
public class Dog : Animal
{
public override void Bark()
{
Console.WriteLine("狗狗旺旺的叫");
}
public override string Name
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
}
public class Cat : Animal
{
public override void Bark()
{
Console.WriteLine("猫咪喵喵的叫");
}
public override string Name
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
}
关于抽象类需要注意的几点:
1)需要用abstract关键字标记
2)抽象方法不能有任何方法实现
3)抽象成员必须包含在抽象类中
4)由于抽象成员没有任何实现,所以子类必须将抽象成员重写(以override来标记)。
5)抽象类不能被实例化
6)抽象类的作用:为了让子类继承
7)抽象方法不能用static修饰
因为:抽象方法是没有任何方法实现的,如果直接通过类名来调用,这样的方法无法执行,没有任何意义;
能调用抽象方法的只能是重写了抽象方法的子类的对象(如果抽象类的子类也是抽象类的话,就无法调用)