继承与多态
一。继承简介,基本语法
1.基本语法
(1)创建类A:class A:
{}
(2)继承于类A的B:class B:
{}
2.继承有什么用
(1)子类对象可以使用父类的字段和函数,没有重名的情况下,可以直接使用字段或者函数进行访问。
(2)子类对象可以对父类的字段进行修改,对父类的字段、函数进行重写需要用new修饰符。
(下面的例子二维点类派生了三维点类)
public class Point //基类
{
public int x, y;
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
public void Print()
{
Console.WriteLine("我是一个二维下的点坐标");
Console.WriteLine("{0},{1}", x, y);
}
}
public class Point3D : Point//继承
{
public int z;
public Point3D(int x, int y, int z) : //使用base构造基类
base(x, y)
{
this.z = z;
}
public new void Print()//new修饰符隐藏基类的Print函数,不加new不hi报错,但会有一个警告。最好还是加上把
{
Console.WriteLine("我是一个三维下的点坐标");
Console.WriteLine("{0},{1},{2}", x, y, z);
}
}
class 类继承
{
static void Main(string[] args)
{
Point point1 = new Point(1, 2);
point1.Print();
Point3D point2 = new Point3D(1, 2,3);
point2.Print();
Console.ReadLine();
}
}
二。关于继承时的构造函数和base关键字的用法
1.构造函数
(1)父类的构造函数无参时子类在使用构造参数时会自动调用。
(2)父类的构造函数有参数时在子类中需要手动指定参数,例如上面的在子类的构造参数后面需要有:base(参数)
2.base用法(相当于python和java中的super关键字)
通过new操作符的修饰的字段、方法会把父类的字段、方法隐藏。因此通过base.字段或方法来访问。
例如在上面的例子中new修饰符把基类Point的Print方法隐藏,我们可通过super方法对它这个方法进行访问。
public new void Print()
{
base.Print(); //成功访问父类的print方法。
Console.WriteLine("我是一个三维下的点坐标");
Console.WriteLine("{0},{1},{2}", x, y, z);
}
三。多态性
1.virtual,override关键字介绍。
只是把上面的例子中基类中Print声明为virtual,子类中的声明为override。表示对他的重写,并去掉new。表面上执行的效果以前一模一样。
public class Point //基类
{
public int x, y;
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
virtual public void Print()
{
Console.WriteLine("我是一个二维下的点坐标");
Console.WriteLine("{0},{1}", x, y);
}
}
public class Point3D : Point//继承
{
public int z;
public Point3D(int x, int y, int z) :
base(x, y)
{
this.z = z;
}
override public void Print()
{
Console.WriteLine("我是一个三维下的点坐标");
Console.WriteLine("{0},{1},{2}", x, y, z);
}
}
class 类继承
{
static void Main(string[] args)
{
Point point1 = new Point(1, 2);
point1.Print();
Point3D point2 = new Point3D(1, 2,3);
point2.Print();
Console.ReadLine();
}
}
2.多态性是什么?
(1)对第一次、第二次的代码主函数中写以下的部分。很容易发现,我们第二次的两个类更符合我们的设想,因为我们创建的是Point和Point3D类的对象。
虽然我们声明的时候都是以基类Point声明的,但是我们创建对象的时候是用不同的类。这就叫类型的转化。可以把子类转化为用父类表示,因为变量内部存储的是对象地址,存储父类地址的空间也可用于存储子类。
Point point1 = new Point(1, 2);
point1.Print();
Point point2 = new Point3D(1, 2, 3);
point2.Print();
(2)有上面的例子我们可一看见virtual和override关键字修饰的类可以和类型的转换搭配使用,我们在不知道以后这个变量要存储哪种类型的对象时,可以先申请一种它父类类型的空间。
(3)多态性:就是申请了同种类型的指针调用相同的方法差生了不同的结果,就像第二图中所示。
(4)注意:用new和override函数修饰的方法要与父类中完全相同。
抽象类
(1)概念:可以把这个类看作是一种特殊的类,这种类不能创建对象,他只有被继承才有实在的意义。因此不能把它声明为sealed(密封类)
(2)从一个实际例子来看:我们先定义一个类:Animal,是动物一定就有吃这个方法,但是每种动物吃的东西不一样。食草动物吃草,食肉动物吃肉
abstract class Animal
{
public abstract void Eat();
}
class EatMeatAnimal:Animal
{
public override void Eat()
{
Console.WriteLine("吃肉");
}
}
class EatGrassAnimal : Animal
{
public override void Eat()//override必须写
{
Console.WriteLine("吃草");
}
}
class 抽象类抽象方法
{
static void Main1(string[] args)
{
//抽象类不能创建对象
Animal m = new EatMeetAnimal();
Animal g = new EatGrassAnimal();
m.Eat();
g.Eat();
Console.ReadLine();
}
}
3.可以看到声明的语法。
(1)父类用abstract修饰,并且有至少一个函数也被abstract修饰并且只有函数头部。
(2)子类中用override方法用来重写
(3)抽象类的子类如果没有重写抽象方法,则子类也是一个抽象类。
四。接口
1.背景:C#只提供单继承,我们如果想要实现多继承,怎么办?接口就是我们的解决方法
2.通过抽象类的学习,我们发现抽象类是不是非常的鸡肋,声不声明有什么用?只不过不允许抽象类本身创建对象。接口可以完全取代抽象类。既然不让创建创建一个animal类,你就不要写这个类了,你写了还不让我用,你说你贱不贱。
3.语法
(1)interface 接口名
{函数头部}
(2)class 类: 接口名
(3)一个类可以使用多个接口,但只可以继承一个类。因此我们把想要实现的函数可以都放在接口中。
4.把animal声明为接口。
interface Animal
{
void Eat();
}
class EatMeetAnimal:Animal
{
public void Eat()
{
Console.WriteLine("吃肉");
}
}
class EatGrassAnimal : Animal
{
public void Eat()//override必须写
{
Console.WriteLine("吃草");
}
}
class 接口
{
static void Main(string[] args)
{
//接口就不是类
Animal m = new EatMeetAnimal();
Animal g = new EatGrassAnimal();
m.Eat();
g.Eat();
Console.ReadLine();
}`.