【技术教程】C#面向对象-封装、继承、多态

面向对象(OOP)是C#编程语言的核心概念之一.它通过类和对象的方式来组织代码,提供了更高的代码复用性,可拓展性和可维护性
OOP的四大基本特征是封装,继承,多态和抽象.这些概念共同构成了OOP的核心原则
不过,有时候人们会提到三大特性(即封装,继承,多态),这通常是将抽象和封装合并讨论,因为两者都涉及到隐藏实现细节

一.类与对象

类是一个模板或者说是一个蓝图,用于创建对象.它定义了对象的属性和行为 类可以包含字段,属性,方法,事件,构造函数等,使用Class关键字来声明一个类,类可以包含访问修饰符(如public,private等)来控制其可见性。

对象

在C#中,对象是类的实例化实体,通过new关键字在堆内存中动态分配空间并创建:执行new ClassName()时,系统自动调用匹配的构造函数(默认或参数化)完成初始化,生成包含独立属性和方法的对象,可通过引用访问其成员,生命周期由垃圾回收器自动管理。

代码

using System;

// 1. 类 = 模板
public class Phone
{
    // 字段(内部状态)
    private string _brand;

    // 属性(对外接口)
    public string Brand
    {
        get => _brand;
        set => _brand = value;
    }

    // 方法(行为)
    public void Call(string number)
    {
        Console.WriteLine($"[{Brand}] 正在拨号:{number}");
    }

    // 构造函数(诞生仪式)
    public Phone(string brand)
    {
        Brand = brand;
        Console.WriteLine($"新手机[{brand}] 已出厂");
    }
}

// 2. 对象 = 实例化后的实体
class Program
{
    static void Main()
    {
        // new 三步:开堆空间 → 调用构造函数 → 返回引用
        Phone myPhone = new Phone("Xiaomi");
        myPhone.Call("10086");
    }
}

二.继承

1.定义

继承是面向对象编程中用于实现代码重用和逻辑扩展的机制。一个类(子类)可以继承另一个类(父类)的属性和方法,子类可以重用父类的代码,并且可以添加新的功能或重写父类的方法。

2.实现方式

  • 使用冒号 : 来表达继承关系
  • C#只支持单继承,一个类只能有一个直接父类,但可以实现多个接口

代码示例

// 父类:Animal   
public class Animal   
{
    public string Name { get; set; }
 
    public void Eat()
    {
        Console.WriteLine($"{Name} 正在吃东西。");
    }   
}
   
// 子类:Dog,继承自Animal   
public class Dog : Animal   
{
    public void Bark()
    {
        Console.WriteLine($"{Name} 正在汪汪叫。");
    }
}
//Dog类继承自Animal类,获得了Name属性和Eat方法。
//Dog类新增了Bark方法。
//子类可以直接使用父类的成员,实现了代码重用。

三.多态

1.定义

多态是指同一操作在不同对象上具有不同的表现形式.通过多态,可以使用统一的接口来调用不同对象的特定实现

2.实现方式

  • 方法重写(Override):子类重写父类的虚方法
  • 接口的实现:不同类实现相同的接口方法
  • 方法重载:同一类中方法名相同,但参数列表不同(严格来说,这是编译时多态)

代码示例

1.继承重写方法实现

// 父类:Animal   
public class Animal   
{
    public string Name { get; set; }
 
    // 虚方法,可以被子类重写
    public virtual void Speak()
    {
        Console.WriteLine($"{Name} 正在发出声音。");
    }   
}
   
// 子类:Dog   
public class Dog : Animal   
{
    // 重写父类的Speak方法
    public override void Speak()
    {
        Console.WriteLine($"{Name} 正在汪汪叫。");
    }   
}
   
// 子类:Cat   
public class Cat : Animal   
{
    // 重写父类的Speak方法
    public override void Speak()
    {
        Console.WriteLine($"{Name} 正在喵喵叫。");
    }    
}    

2.实现接口

// 定义接口    
public interface IShape    
{
    double GetArea();    
}
    
// 实现接口的类:Circle    
public class Circle : IShape    
{
    public double Radius { get; set; }
 
    public double GetArea()
    {
        return Math.PI * Radius * Radius;
    }    
}
    
// 实现接口的类:Rectangle    
public class Rectangle : IShape    
{
    public double Width { get; set; }
    public double Height { get; set; }
 
    public double GetArea()
    {
        return Width * Height;
    }
}

说明:

方法重写:在父类中定义虚方法(virtual),在子类中使用override关键字重写
接口实现:不同类实现相同接口的方法,可以通过接口引用来调用具体实现
多态调用:通过父类或接口的引用,调用子类或具体实现的方法

List<Animal> animals = new List<Animal>   
{
    new Dog { Name = "小黑" },
    new Cat { Name = "小白" },
    new Animal { Name = "未知动物" }   
};
   
foreach (var animal in animals)   
{
    animal.Speak();   
}   
/* 输出:   
小黑 正在汪汪叫。   
小白 正在喵喵叫。   
未知动物 正在发出声音。   
*/
   
// 接口多态   
List<IShape> shapes = new List<IShape>   
{
    new Circle { Radius = 5 },
    new Rectangle { Width = 4, Height = 6 }
};
 
foreach (var shape in shapes)
{
    Console.WriteLine($"面积:{shape.GetArea()}");
}
/* 输出:
面积:78.5398163397448
面积:24
*/

四.抽象

1.定义

抽象是对现实世界复杂对象的建模,提取出关键特性,忽略不必要的细节.抽象可以通过抽象类和接口来实现,提供一个模板,让子类实现特定的功能

2.实现方式

  • 抽象类(Abstract Class):使用abstract关键字修饰,不能实例化,可以包含抽象方法和非抽象方法
  • 接口(Interface):定义一组未实现的方法或属性,需要由实现类提供具体实现

3.代码示例

抽象类

// 抽象类:Shape   
public abstract class Shape   
{
    // 抽象方法,没有方法体,子类必须实现
    public abstract double GetArea();
 
    // 普通方法,子类可直接使用或重写
    public virtual void Display()
    {
        Console.WriteLine("这是一个形状。");
    }   
}
   
// 子类:Circle   
public class Circle : Shape   
{
    public double Radius { get; set; }
 
    // 实现抽象方法
    public override double GetArea()
    {
        return Math.PI * Radius * Radius;
    }
 
    // 重写父类方法
    public override void Display()
    {
        Console.WriteLine($"这是一个半径为{Radius}的圆形。");
    }   
}
   
// 子类:Rectangle   
public class Rectangle : Shape   
{
    public double Width { get; set; }
    public double Height { get; set; }
 
    // 实现抽象方法
    public override double GetArea()
    {
        return Width * Height;
    }
 
    // 重写父类方法
    public override void Display()
    {
        Console.WriteLine($"这是一个宽为{Width},高为{Height}的矩形。");
    }   
}   

接口

// 接口:IMovable   
public interface IMovable   
{
    void Move(double distance);   
}
   
// 实现接口的类:Car   
public class Car : IMovable
{
    public void Move(double distance)
    {
        Console.WriteLine($"汽车行驶了{distance}公里。");
    }
}
 
// 实现接口的类:Person
public class Person : IMovable
{
    public void Move(double distance)
    {
        Console.WriteLine($"人行走了{distance}公里。");
    }    
}    

说明:

抽象类:不能被实例化,提供了一个模板或基类,强制子类实现抽象方法
接口:定义了行为的契约,实现类必须实现接口中的所有成员
抽象类与接口的区别:
抽象类可以包含已实现的方法和字段,接口只能包含未实现的方法(C# 8.0开始,接口可以有默认实现)
一个类只能继承一个抽象类,但可以实现多个接口

List<Shape> shapes = new List<Shape>    
{
    new Circle { Radius = 5 },
    new Rectangle { Width = 4, Height = 6 }    
};
    
foreach (var shape in shapes)    
{
    shape.Display();
    Console.WriteLine($"面积:{shape.GetArea()}");
}
/* 输出:
这是一个半径为5的圆形。
面积:78.5398163397448
这是一个宽为4,高为6的矩形。
面积:24
*/
 
// 接口的使用
List<IMovable> movables = new List<IMovable>
{
    new Car(),
    new Person()
};
 
foreach (var movable in movables)
{
    movable.Move(10);
}
/* 输出:
汽车行驶了10公里。
人行走了10公里。
*/

总结

  • 封装:通过访问修饰符和属性,保护对象的内部状态,提供受控的访问接口
  • 继承;子类继承父类的属性和方法,实现代码重用和逻辑扩展
  • 多态:通过方法重写和接口实现,实现相同接口的不同表现形式,增强代码的灵活性和可扩展性
  • 抽象:通过抽象类和接口,定义对象的抽象模型,强制子类实现特定的行为

© 版权声明
THE END
喜欢就支持一下吧
点赞12 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容