22实现多态之抽象类和抽象方法
抽象类和抽象方法
多个类抽象出一个父类,这个类就是抽象类,在这个类里提供一些抽象的成员,让子类去重写,不同的子类可以重写出不同的结果,以此实现多态。
当父类中的虚方法不知道如何去写实现的时候,可以考虑将父类写成抽象类,将方法写成抽象方法。
这是领导思维,设置一个中层,让中层去带调用各个底层的实现,而不用高层去调用各个底层的成员。
抽象类就是领导(抽象父类),发发命令就好,具体实现下面小兵(子类)负责。
抽象类的作用:为了被子类继承,从而实现多态。是一种约定,约定必须要具体那些方法。
抽象函数作用:都是为了被子类重写,重写实现多态(同一个对象同一个方法,指向不同从而实现多态)
抽象类的特点
1.抽象成员必须标记为abstract,并且不能有任何实现。
2.抽象成员必须在抽象类中。
3.抽象类不能被实例化
4.子类继承抽象类后,必须把父类中的所有抽象成员都重写。(除非子类也是一个抽象类,则可以不重写)
5.抽象成员的访问修饰符不能是private
6.在抽象类中可以包含实例成员。并且抽象类的实例成员可以不被子类实现
7.抽象类是有构造函数的。虽然不能被实例化。
8、如果父类的抽象方法中有参数,那么。继承这个抽象父类的子类在重写父类的方法的时候必须传入对应类型的参数。如果抽象父类的抽象方法中有返回值,那么子类在重写这个抽象方法的时候 也必须要传入返回值。
使用情况
如果父类中的方法有默认的实现,并且父类需要被实例化,这时可以考虑将父类定义成一个普通类,用虚方法来实现多态。
如果父类中的方法没有默认实现,父类也不需要被实例化,则可以将该类定义为抽象类。
虚函数和抽象函数的异同点:
相同点: 都可以被子类重写从而实现多态
不同点:
1:虚函数有方法体,抽象函数没有方法体。也就是说虚函数可以有默认实现,抽象函数不行
2:虚函数可以被重写,也可以不被重写,抽象函数必须被重写
3:抽象方法只能在抽象类中,抽象方法不能在普通类中
抽象类和普通类的异同点:
相同点:都可以被继承,也可以继承其他类,都可以有普通方法
不同点:
1:普通类可以被实例化,抽象类不行,抽象类提供一种约定一种类的模板,不能被实例化,因为实例化是没有意义,具体的类有实现才有意义
2:抽象类才能有抽象方法,普通类不行
基础使用
抽象父类:Animal
子类:Cat、Dog
public abstract class Animal
{
public abstract void Bark();
}
public class Cat : Animal
{
public override void Bark()
{
Console.WriteLine("猫喵喵叫");
}
}
public class Dog : Animal
{
public override void Bark()
{
Console.WriteLine("狗汪汪叫");
}
}
实例化两个子类调用同一个方法
Animal animal = new Cat();
Animal animal2 = new Dog();
animal.Bark();
animal2.Bark();
练习使用多态求矩形的面积和周长以及圆的面积和周长
父类,抽象类
//抽象类,这个类专门用来获取面积
public abstract class Shape
{
//获得面积
public abstract double GetArea();
//获得周长
public abstract double GetPerimeter();
}
两个子类:圆类和矩形类
//圆类
public class Circle : Shape
{
//构造函数,给半径字段赋值
public Circle(double r)
{
this.R = r;
}
//半径的字段
private double _r;
//半径的属性
public double R
{
get { return _r; }
set { _r = value; }
}
//获得面积
public override double GetArea()
{
return Math.PI * this.R * R;
}
//获得周长
public override double GetPerimeter()
{
return Math.PI * this.R * 2;
}
}
//矩形类
public class Rectangle : Shape
{
//构造函数,给宽和长字段赋值
public Rectangle(double l, double w)
{
this.RectangleWidth = w;
this.RectangleLenth = l;
}
//长的字段
private double _rectangleLenth;
//长的属性
public double RectangleLenth
{
get { return _rectangleLenth; }
set { _rectangleLenth = value; }
}
//宽的字段
private double _rectangleWidth;
//宽的属性
public double RectangleWidth
{
get { return _rectangleWidth; }
set { _rectangleWidth = value; }
}
//获得面积
public override double GetArea()
{
return this.RectangleLenth * this.RectangleWidth;
}
//获得周长
public override double GetPerimeter()
{
return this.RectangleLenth * 2 + this.RectangleWidth * 2;
}
}
声明调用即可
Shape shape1 = new Circle(3.5);
double s1 = shape1.GetArea();
double c1 = shape1.GetPerimeter();
Console.WriteLine("圆的面积为:{0:0.00},周长为{1:0.00}", s1,c1);
Shape shape2 = new Rectangle(3,5);
double s2 = shape2.GetArea();
double c2 = shape2.GetPerimeter();
Console.WriteLine("矩形的面积为:{0:0.00},周长为{1:0.00}", s2, c2);