c#中的重载和重写区别

  重载的条件:
          1.必须在同一个类中2.方法名必须相同3.参数列表不能相同。
   重写的条件:
          1. 在不同的类中
          2. 发生方法重写的两个方法返回值,方法名,参数列表必须完全一致
          3. 子类抛出的异常不能超过父类相应的方法抛出的异常
          4. 子类方法的访问级别不能低于父类相应方法的访问级别(public,package,protected, private)

          5.方法体不同

super()调用父类构造,super.只能调用父类的实例方法
this()调用该类的其他构造方法,this.调用类的属性,方法
如果父类有有参构造,子类必须定义构造方法

重载:

       重载发生在同一个类中;重载主要是针对同一个类中方法名相同但参数(必须的)不同或返回类型(不是必须的)不同的情况。可以参照如下的代码


class OverLoadTest
    {
        public void Hello()
        {
        }
        public void Hello(string str)
        {
        }
        public string Hello()
        {
        }
    }
在这段代码中有三个具有相同名称的方法Hello,他们彼此之间是重载的关系,注意两点:他们共同存在于一个类中,虽有同样的名字但是执行不同的操作;第一个方法和第三个方法只有返回类型不同,这在C# 中是不允许的,编译器会报出“已定义一个名为"Hello"的方法”的错误。


重写:

      重写发生在有继承关系的类之间
      重写发生在派生类上,通过override关键字来改写从其父类继承过来的具有相同返回值,方法名称和参数列表的方法。

    class Program
    {
        static void Main(string[] args)
        {
            OverWriteTestTT owTT = new OverWriteTestTT();
            owTT.Hello();
            overWriteTestTTT owTTT = new overWriteTestTTT();
            owTTT.Hello();
        }
    }
    class OverWriteTest
    {
        //Over write the method ToString();
        public override string ToString()
        {
            return "hello world";
        }
        //Define a virtual method Hello() to be over written
        public virtual void Hello()
        {
            Console.WriteLine("hello");
        }
    }
    class OverWriteTestTT : OverWriteTest
    {
        public override void Hello()
        {
            Console.WriteLine("No hello world");
        }
    }
    class overWriteTestTTT : OverWriteTestTT
    {
        //Over write the method Hello() of class OverWriteTestTT
        public override void Hello()
        {
            base.Hello();
            Console.WriteLine("NNo hello world");
        }
    }
上面这段代码演示了如何对父类的方法进行重写,需要注意的地方有两点:可以在子类中被重写的方法一定要被标记成virtual(虚拟), abstract(抽象), override(重写)标记为virtual 和abstract 的函数就是为了重写而创建的,标记为override的函数本身是由前两种函数重写而来的,所以它可以被重写也是顺理成章的了;重写的函数必须在子类中出现,而且任何一个父类的函数在其一个子类中只能被重写一次。(这一点很好理解,当你要重写两次时,该子类中将定义两个返回类型,方法名称 和参数列表都相同的函数,这肯定是不可能的)。
<think>我们被要求解释C#重载(Overload)重写(Override)的区别。这是一个面向对象编程中的基础概念,我们需要清晰地解释两者的定义、使用场景区别,并给出代码示例。 ###重载(Overload)的定义重载发生在同一个类中,方法名相同但参数列表不同(参数类型、个数或顺序不同)。重载返回值类型无关,主要目的是提供多种方式来处理不同的输入。###重写(Override)的定义重写发生在继承关系中,子类重新定义父类中已经声明为virtual或abstract的方法。重写要求方法签名(方法名参数列表)必须父类方法完全一致,主要目的是实现多态性。###主要区别1. **发生位置**:重载在同一个类中,重写在子类中。2.**参数要求**:重载要求参数列表不同,重写要求参数列表相同。 3. **返回类型**:重载可以有不同的返回类型(但仅返回类型不同不能构成重载),重写要求返回类型相同(C#9开始支持协变返回类型)。4.**访问修饰符**:重载可以有不同的访问修饰符,重写不能改变父类方法的访问级别。5.**多态性**:重载是编译时多态(静态多态),重写是运行时多态(动态多态)。 ###代码示例####重载示例```csharppublic classCalculator{//第一个Add方法,接受两个整数publicint Add(int a, intb){returna +b;}//重载Add方法,接受三个整数publicint Add(int a, intb,int c){return a+ b+ c;}//重载Add方法,接受两个双精度浮点数publicdouble Add(double a, doubleb){returna +b;}//注意:以下代码不能上面的intAdd(inta,int b)同时存在,因为仅返回类型不同不能重载//public doubleAdd(inta,int b) {returna +b;} }//使用varcalc =new Calculator(); Console.WriteLine(calc.Add(1,2));//调用第一个Add,输出3Console.WriteLine(calc.Add(1,2,3));//调用第二个Add,输出6Console.WriteLine(calc.Add(1.5,2.5));//调用第三个Add,输出4.0``` ####重写示例```csharppublicclass Animal{publicvirtual voidMakeSound(){Console.WriteLine("Animalmakes asound");}} publicclass Dog: Animal{publicoverride voidMakeSound(){Console.WriteLine("Dogbarks: Woof!");}} publicclass Cat: Animal{publicoverride voidMakeSound(){Console.WriteLine("Catmeows: Meow!");}} //使用Animal myDog= newDog();AnimalmyCat= newCat();myDog.MakeSound();//输出:Dog barks:Woof! myCat.MakeSound(); //输出: Catmeows: Meow!//如果没有重写,则调用基类方法Animal animal= newAnimal();animal.MakeSound(); //输出: Animalmakes asound``` ###对比表格|特性|重载(Overload)|重写(Override)||--------------|----------------------------------------|----------------------------------------| |**发生位置**|同一个类中|子类中| |**方法签名**|必须不同(参数类型、个数或顺序)|必须相同| |**返回类型**|可以不同(但仅返回类型不同不能重载)|必须相同(C#9+支持协变返回)| |**访问修饰**|可以不同|不能比基类方法更严格| |**多态性**|编译时多态(静态)|运行时多态(动态)| |**关键字**|不需要关键字|需要`virtual``override`| |**继承要求** |不需要继承关系|必须有继承关系|###注意事项1.**重载解析**:编译器根据参数类型数量在编译时决定调用哪个重载方法。2.**重写条件**:只有标记为`virtual`、`abstract`或`override`(基类中)的方法才能被重写。 3. **隐藏(new)重写**:如果子类中声明了基类同名的方法但没有使用`override`,则使用`new`关键字(可显式或隐式)表示隐藏,这不同于重写。隐藏不会实现多态。###隐藏(new)重写(override)的简单对比```csharppublicclass Base{publicvirtual voidMethod() =>Console.WriteLine("Base"); }public classDerivedOverride: Base{publicoverride voidMethod()=> Console.WriteLine("DerivedOverride");} publicclass DerivedNew :Base{public newvoid Method() =>Console.WriteLine("DerivedNew"); }//使用Base b1 =new DerivedOverride();b1.Method(); //输出: DerivedOverride (多态) Baseb2= newDerivedNew(); b2.Method(); //输出: Base(因为隐藏,所以调用基类方法)DerivedNew d= newDerivedNew(); d.Method();//输出:DerivedNew``` ###总结-重载:同一类中,同名方法不同参数,编译时决定调用。-重写:子类重写父类方法,实现多态,运行时根据对象类型决定调用。---§§相关问题§§:1. C#中`new`关键字在方法隐藏中的具体行为是什么?2.什么是协变返回类型?C#中如何实现?3.在方法重载中,如果参数类型存在继承关系,编译器如何解析?4.抽象方法(abstract)虚方法(virtual)在重写时有何异同?</think>### C#重载(Overload)重写(Override)的区别详解 重载(Overload)重写(Override)是C#中两个核心但完全不同的面向对象概念,它们在目的、实现方式应用场景上有本质区别: #### 核心区别对比表 | 特性 | 重载(Overload) | 重写(Override) | |--------------|------------------------------------|---------------------------------| | **发生位置** | 同一个类中 | 继承关系的派生类中 | | **目的** | 提供同一操作的多种实现方式 | 修改或扩展基类行为 | | **方法签名** | 必须不同(参数类型/数量/顺序) | 必须完全相同 | | **多态性** | 编译时多态(静态绑定) | 运行时多态(动态绑定) | | **关键字** | 不需要特殊关键字 | 需要`virtual``override` | | **返回类型** | 可以不同 | 必须相同(C#9+支持协变返回) | | **继承要求** | 不需要继承关系 | 必须有继承关系 | --- ### 代码示例详细解释 #### 1. 重载(Overload)示例 ```csharp public class Calculator { // 重载1: 两个整数相加 public int Add(int a, int b) { Console.WriteLine($"Adding integers: {a} + {b}"); return a + b; } // 重载2: 三个整数相加(参数数量不同) public int Add(int a, int b, int c) { Console.WriteLine($"Adding three integers: {a} + {b} + {c}"); return a + b + c; } // 重载3: 两个双精度数相加(参数类型不同) public double Add(double a, double b) { Console.WriteLine($"Adding doubles: {a} + {b}"); return a + b; } // 重载4: 整数字符串相加(参数顺序不同) public string Add(string a, int b) { Console.WriteLine($"Concatenating: {a} + {b}"); return a + b.ToString(); } // 错误示例:仅返回类型不同不能构成重载 // public double Add(int a, int b) { return (double)(a + b); } } // 使用 var calc = new Calculator(); calc.Add(2, 3); // 调用第一个Add calc.Add(1.5, 2.5); // 调用第三个Add calc.Add("Result: ", 5); // 调用第四个Add ``` #### 2. 重写(Override)示例 ```csharp public class Shape { // 虚方法 - 可被重写 public virtual void Draw() { Console.WriteLine("Drawing a generic shape"); } // 非虚方法 - 不能被重写 public void DisplayInfo() { Console.WriteLine("Shape information"); } } public class Circle : Shape { // 重写基类虚方法 public override void Draw() { Console.WriteLine("Drawing a circle"); base.Draw(); // 可选调用基类实现 } // 错误示例:不能重写非虚方法 // public override void DisplayInfo() { } } public class Square : Shape { // 重写基类虚方法 public override void Draw() { Console.WriteLine("Drawing a square"); } } // 使用多态 Shape circle = new Circle(); Shape square = new Square(); circle.Draw(); // 输出: Drawing a circle \n Drawing a generic shape square.Draw(); // 输出: Drawing a square ``` #### 3. 重载重写结合使用 ```csharp public class DatabaseLogger { // 基类方法 - 可被重写 public virtual void Log(string message) { Console.WriteLine($"LOG: {message}"); } // 重载方法1 public void Log(string message, int severity) { Console.WriteLine($"[{severity}] {message}"); } } public class EncryptedLogger : DatabaseLogger { // 重写基类方法 public override void Log(string message) { string encrypted = Encrypt(message); base.Log(encrypted); } // 重载方法2(在派生类中) public void Log(string message, string category) { Console.WriteLine($"[{category}] {message}"); } private string Encrypt(string input) => new string(input.Reverse().ToArray()); } // 使用 DatabaseLogger logger = new EncryptedLogger(); logger.Log("Sensitive data"); // 调用重写方法,输出加密内容 var encLogger = new EncryptedLogger(); encLogger.Log("Info message", "SECURITY"); // 调用派生类重载 ``` --- ### 关键区别详解 1. **绑定时机不同** - 重载:编译时决定调用哪个方法(早期绑定) ```csharp var calc = new Calculator(); calc.Add(1, 2); // 编译时确定调用int Add(int, int) ``` - 重写:运行时根据实际对象类型决定(晚期绑定) ```csharp Shape shape = new Circle(); shape.Draw(); // 运行时确定调用Circle.Draw() ``` 2. **方法签名要求** - 重载要求参数列表必须不同: ```csharp // 有效重载 void Method(int a) {} void Method(string a) {} void Method(int a, int b) {} ``` - 重写要求签名完全相同: ```csharp public class Base { public virtual void Test(int x) {} } public class Derived : Base { // 有效重写 public override void Test(int y) {} // 参数名可不同 // 无效:参数类型不同 // public override void Test(string x) {} } ``` 3. **继承关系中的行为** - 重载方法在派生类中**不会**自动继承重载关系 - 重写方法在派生类中形成多态链 4. **异常处理差异** - 重载方法可以抛出不同的异常类型 - 重写方法不能抛出比基类方法更宽泛的异常: ```csharp public class Base { public virtual void Process() throws IOException { } } public class Derived : Base { // 有效 public override void Process() { } // 无效:不能抛出更宽泛异常 // public override void Process() throws Exception { } } ``` --- ### 实际应用场景 1. **重载的典型应用** ```csharp // 数学计算类 public class MathOperations { public int Max(int a, int b) => (a > b) ? a : b; public double Max(double a, double b) => (a > b) ? a : b; public int Max(int a, int b, int c) => Max(Max(a, b), c); } ``` 2. **重写的典型应用** ```csharp // 游戏实体系统 public abstract class GameEntity { public virtual void Update() { /* 基础更新逻辑 */ } } public class Player : GameEntity { public override void Update() { base.Update(); // 保留基础行为 // 玩家特有更新逻辑 } } public class Enemy : GameEntity { public override void Update() { // 完全重写的敌人行为 } } ``` ---
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值