C# 最基础知识介绍--多态
在C#中,多态是面向对象编程(OOP)中的常见概念,它允许不同类型的对象对相同的消息作出响应。简单地说,多态就是对象(或方法)有不同的表现形式。
多态性有三种形式:静态,动态和协变。下面我们会一一解释。
静态多态
静态多态性是在编译时确定的,在程序执行之前,就确定了发生的方法和参数。在编程语言C#中,静态多态性可以通过函数重载和运算符重载实现。每个函数都必须有一个唯一的名字,并且参数的数量和类型必须不同,但是在编译时确定。
以函数重载为例,假设我们有以下两个函数定义,分别实现了对数值的平方和对字符串的拼接操作。
static int Square(int n)
{
return n * n;
}
static string Concat(string s1, string s2)
{
return s1 + s2;
}
我们可以看到,这两个函数的名称都是不同的,他们可以同时存在于同一个程序中。
同时,由于函数的参数类型和数量不同,使得函数的调用必须显式地指明参数类型,所以编译器知道调用哪个函数。
int result = Square(3);
string str = Concat("hello", "world");
动态多态
动态多态性是在程序运行时确定的,使用基类声明的指针或引用可以指向派生类的对象。这里主要涉及到继承和虚函数的使用。
例如:
class Shape
{
public virtual double Area()
{
return 0;
}
}
class Circle : Shape
{
double radius;
public Circle(double r)
{
radius = r;
}
public override double Area()
{
return 3.14 * radius * radius;
}
}
class Rectangle : Shape
{
double length;
double width;
public Rectangle(double l, double w)
{
length = l;
width = w;
}
public override double Area()
{
return length * width;
}
}
在上面的代码示例中,我们定义了一个基类 Shape
和两个继承类 Circle
和 Rectangle
。同时,Shape
中定义了一个虚函数 Area(),派生类可以覆盖这个方法来实现不同的功能。重点是在声明的时候使用了关键字 virtual
和继承类中重写的关键字 override
。
现在,我们可以通过基类的引用调用覆盖之后的方法,这里就是通过定义 Shape
类型的变量来指向两个派生类的实例,实现了运行时的多态性。
Shape shape1 = new Circle(3);
Shape shape2 = new Rectangle(4, 5);
double area1 = shape1.Area();
double area2 = shape2.Area();
协变
协变允许派生类的方法返回基类的对象。换句话说,协变可以将派生类作为基类来使用。
例如:
interface ICovariant<out T>
{
T Get();
}
class Animal { }
class Cat : Animal { }
class CovariantCat : ICovariant<Cat>
{
public Cat Get()
{
return new Cat();
}
}
class CovariantAnimal : ICovariant<Animal>
{
public Animal Get()
{
return new Animal();
}
}
在上面的代码示例中,我们定义了一个协变接口 ICovariant<T>
,其中 out
关键字表示协变。然后定义了两个派生类 CovariantCat
和 CovariantAnimal
,显然 CovariantCat
中的 Get()
方法返回的是 Cat
类型的对象,而 CovariantAnimal
中的 Get()
方法返回的是 Animal
类型的对象,但是由于使用了协变,这个方法也可以将派生类的实例也返回给基类。
ICovariant<Animal> animal = new CovariantCat();
Animal animalObj = animal.Get();
在这个示例中,我们将 CovariantCat
类型的对象赋值给 ICovariant<Animal>
类型的变量。此时,使用 Get()
方法从接口中获取的对象仍然是 Cat
类型,但是编译器会将它转换成 Animal
对象,以允许将派生类对象作为基类来使用。
示例说明
下面举两个具体的例子来说明多态的使用方法。
示例一:吃饭
class Animal
{
public virtual void Eat()
{
Console.WriteLine("动物在吃...");
}
}
class Cat : Animal
{
public override void Eat()
{
Console.WriteLine("猫在吃鱼...");
}
}
class Dog : Animal
{
public override void Eat()
{
Console.WriteLine("狗在吃肉...");
}
}
在上面的代码中,我们定义了一个抽象的 Animal
类,然后 Cat
和 Dog
类都继承自 Animal
类。同时,Animal
类中定义了一个 Eat()
方法。Cat
和 Dog
类都重写了 Eat()
方法。
然后我们可以创建一个 List<Animal>
来表示动物园中的动物们,然后调用它们的 Eat()
方法。
List<Animal> animals = new List<Animal>();
animals.Add(new Cat());
animals.Add(new Dog());
foreach (Animal animal in animals)
{
animal.Eat();
}
输出结果如下:
猫在吃鱼...
狗在吃肉...
我们可以看到,由于 Cat
和 Dog
类重写了 Eat()
方法,调用 List<Animal>
类型的对象的 Eat()
方法时,会根据实际执行的对象来调用对应的方法。这种由对象的实际类型来决定方法的调用方式,就是运行时多态。
示例二:图形面积计算
abstract class Shape
{
public abstract double Area();
}
class Circle : Shape
{
double radius;
public Circle(double r)
{
radius = r;
}
public override double Area()
{
return 3.14 * radius * radius;
}
}
class Rectangle : Shape
{
double length;
double width;
public Rectangle(double l, double w)
{
length = l;
width = w;
}
public override double Area()
{
return length * width;
}
}
在上面的代码中,我们定义了一个抽象的 Shape
类,然后 Circle
和 Rectangle
类都继承自 Shape
类。同时,Shape
类中定义了一个抽象的 Area()
方法。Circle
和 Rectangle
类都实现了这个方法。
然后我们可以创建一个 List<Shape>
来表示各种形状的图形,然后计算它们的面积。
List<Shape> shapes = new List<Shape>();
shapes.Add(new Circle(3));
shapes.Add(new Rectangle(4, 5));
foreach (Shape shape in shapes)
{
Console.WriteLine("面积是:" + shape.Area());
}
输出结果如下:
面积是:28.26
面积是:20
我们可以看到,由于 Circle
和 Rectangle
类都实现了 Area()
方法,调用 List<Shape>
类型的对象的 Area()
方法时,会根据实际执行的对象来调用对应的方法。这种由对象的实际类型来决定方法的调用方式,也是运行时多态。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C# 最基础知识介绍–多态 - Python技术站