C# 继承和多态

继承和多态

virtual必须重载吗? virtual可以直接调用吗? 多个修饰符之间顺序有要求吗? virtual必须完整定义吗? virtual后使用override和使用new隐藏有什么区别?

在派生类中使用new修饰符可以声明与基类中同名的方法和字段可以隐藏(覆盖)基类的方法和字段. 在基类的方法被隐藏的情况下, 调用派生类对象的方法究竟调用哪个类取决于对象声明的类型. 在c#中, 派生类其实是可以被声明成其基类, 可以跳过其被隐藏. 还用一种访问基类的被隐藏的方法的方法是在派生类中使用base关键字.

如果不希望在使用对象时还操心对象到底在声明时使用的什么类型, 就需要在基类中使用virtual关键字声明方法, 在派生类中使用override修饰方法. 但virtual修饰的对象可以直接通过基类的对象调用吗? 派生类可以不声明override的方法(必须重载吗)吗? 基类中没有使用virtual派生类中可以使用override吗? 基类中没有abstactvirtual修饰符不可以被override. vitural修饰的方法可以直接通过基类的对象直接调用. 派生类可以不重写基类的虚拟方法, 当调用派生类对象的虚拟方法时, 对用的将会是其父类的虚拟方法. 基类中没有虚拟修饰符的方法是不可以被重写的.

abstract用于修饰抽象类和抽象方法. 抽象类没有实例, 而且必须被继承. 抽象方法必须被重载, 重载为一个可以实现的方法或者一个新的抽象方法. 抽象方法定义时没有函数体, 但可以有参数吗? 可以直接使用new覆盖吗? 抽象类里可以声明和调用普通方法和虚拟方法吗? 抽象类中的方法如果不声明abstract是不能不写函数体的, 但这个方法如果不是静态的就不能直接通过类来调用. 换句话说, 通过类来调用的只能是静态成员. 抽象方法只能存在于抽象类中, 不可以在非抽象类中包含. 抽象方法定义时可以有参数, 但重写时需要保证参数类型和数量一致, 另外, 抽象方法不可以不注明返回类型. 基类的抽象方法不可以直接被new覆盖. 可以通过抽象类调用其普通方法, 只不过由于其不能被实例化, 需要将方法声明为静态的, 再通过抽象类访问. 由于需要将方法标记为静态, 并且静态方法不可修饰为虚拟, 所以不可以通过抽象类调用虚拟方法.

sealed用于修饰密封方法和密封类, 密封类不可被继承, 密封方法不可以被重载. 但要注意的是, 密封方法可以在其派生类中使用new给隐藏.

需要注意的是, 构造函数的继承稍显复杂, 如果基类中有声明的带参数的构造函数就需要在派生类中显式继承:

// 基类
public class BaseClass
{
    public BaseClass(type varName)
    {
        ...
    }
    ...
}
// 派生类
public class ChildClass : BaseClass
{
    public ChildClass(type varName) : base(varName)
    {
        ...
    }
    ...
}

c#使用如此多的关键字可能是为了尽可能消除语言的二意性.

设计实验:

  1. 一个方法, 被直接使用new隐藏. 该方法直接被派生类调用, 该方法的对象放在基类的数组中再被调用.
  2. 测试virtual的几个问题.
  3. 直接调用virtual方法.
  4. 尝试使用new隐藏.
  5. 测试abstract的几个问题.
  6. 编码机器抽象类和家用电器半抽象类. 机器抽象方法为启动和关闭. 家用电器继承自机器, 虚拟方法为待机. 设置家用电器数组, 存放空调, 电视实例.
  7. 使用6中的设计实现1-5.
public abstract class Machine
{
  public Machine(string name)
  {
      this.name = name.Trim();
  }
  protected enum Statuses : byte
  {
      off, on, standby
  }
  protected string name;
  public string Name
  {
      get { return name; }
      set { name = value; }
  }
  protected Statuses status = Statuses.off;
  public int StatusByte
  {
      get { return (byte)status; }
  }
  public string StatusString
  {
      get { return status.ToString(); }
  }
  public abstract void On();
  public abstract void Off();
  // public virtual static void Description()
  // 错误 CS0112 静态成员不能标记为“virtual”
  public static void Description()
  {
      Console.WriteLine("I am class Machine, I am an abstract class.");
  }
}

public class ElectricalApp : Machine
{
  public ElectricalApp(string name) : base(name){ }
  // public new void On()
  // 错误 CS0534 “ElectricalApp”不实现继承的抽象成员“Machine.On()”
  public override void On()
  {
      if (this.status == Statuses.on)
      {
          Console.WriteLine($"{this.name}: Already On.");
      }
      else
      {
          this.status = Statuses.on;
          Console.WriteLine($"{this.name}: Turn On!");
      }
  }
  public override void Off()
  {
      if (this.status == Statuses.off)
      {
          Console.WriteLine($"{this.name}: Already Off.");
      }
      else
      {
          this.status = Statuses.off;
          Console.WriteLine($"{this.name}: Turn Off!");
      }
  }
  // public abstract void Standby();
  // 错误 CS0513 “ElectricalApp.Standby()”是抽象的, 但它包含在非抽象类型“ElectricalApp”中
  public virtual void Standby()
  {
      if (this.status == Statuses.standby)
      {
          Console.WriteLine($"{this.name}: Already Standby.");
      }
      else
      {
          this.status = Statuses.standby;
          Console.WriteLine($"{this.name}: Turn Standby.");
      }
  }
  // public override void Test() { } // 在 Machine 中假设有public void Test(){}
  // 错误 CS0506 “ElectricalApp.Test()”: 继承成员“Machine.Test()”未标记为 virtual、abstract 或 override, 无法进行重写
}

public class Television : ElectricalApp
{
   public Television(string name) : base(name){ }
   public override void Standby() // 注意是使用 override 进行方法重写
   {
       if (this.status == Statuses.standby)
       {
           Console.WriteLine($"{this.name}:  Already Standby.");
       }
       else
       {
           this.status = Statuses.standby;
           Console.WriteLine($"Now you can't see anything on {this.name} without Off.");
       }
   }
}
public class AirConditioner : ElectricalApp
{
   public AirConditioner(string name) : base(name){ }
   public new void Standby() // 注意是使用 new 进行方法隐藏
   {
       if (this.status == Statuses.standby)
       {
           Console.WriteLine($"{this.name}:  Already Standby.");
       }
       else
       {
           this.status = Statuses.standby;
           Console.WriteLine($"There's not any air out from {this.name}, but it can be turned on quickly.");
       }
   }
}
internal class Program
{
   static void Main(string[] args)
   {
       // Machine machine = new Machine();
       // 错误 CS0144 无法创建抽象类型或接口“Machine”的实例
       // Machine.On(); // Machine 类中有非静态的public On 方法时
       // 错误 CS0120 对象引用对于非静态的字段、方法或属性“Machine.On()”是必需的

       Machine.Description();
       // 可以通过抽象类本身调用其静态方法.

       ElectricalApp myApp = new ElectricalApp("myApp");
       AirConditioner myAC = new AirConditioner("myAC");
       Television myTV = new Television("myTV");
       ElectricalApp[] myElectricalApps = { myApp, myAC, myTV };
       // ElectricalApp 数组, 其中的元素不一定是 ElectricalApp 类, 还有其派生类.

       Console.WriteLine("\nNow test Television!");
       myElectricalApps[2].Standby();
       // 由于使用的虚拟方法重写, 数组的 ElectricalApp 类声明不影响其派生类方法的调用.
       myTV.On();
       myTV.Standby();

       Console.WriteLine("\nNow test Air-conditioner!");
       myElectricalApps[1].Standby();
       // 使用 new 修饰符覆盖基类的方法, 当派生类被声明为基类时(这里体现在派生类存储与基类数组)
       // 对用的是其被隐藏的基类方法.
       myAC.On();
       myAC.Standby();
   }
}

上述实验输出为:

I am class Machine, I am an abstract class.

Now test Television!
Now you can't see anything on myTV without Off.
myTV: Turn On!
Now you can't see anything on myTV without Off.

Now test Air-conditioner!
myAC: Turn Standby.
myAC: Turn On!
There's not any air out from myAC, but it can be turned on quickly.
<think>好的,我现在需要回答用户关于C#继承多态示例代码的请求。首先,用户引用了三个站内资料,都涉及多态继承以及它们的实现方式,比如虚方法、抽象类接口。用户希望看到具体的代码示例,所以我得结合这些概念来构造示例。 首先,我应该明确继承多态的基本概念。继承允许一个类继承另一个类的属性方法,而多态则让子类可以重写这些方法,实现不同的行为。根据引用[1][2],多态C#中可以通过虚方法、抽象类接口来实现。引用[3]还提到多态的优势,比如灵活性可扩展性,这些应该在示例中体现出来。 接下来,我需要设计几个示例来覆盖不同的实现方式。可能的结构是:首先展示一个基础的继承例子,然后引入虚方法的重写,接着是抽象类,最后是接口。这样用户可以逐步理解不同层次的实现。 对于继承的示例,可以创建一个基类Animal,然后派生类DogCat。基类中有个MakeSound方法,使用虚方法让子类重写。这样在调用时,根据对象的实际类型执行不同的方法,体现多态。 然后,可以引入抽象类的例子,比如Shape抽象类,包含抽象方法CalculateArea,让子类CircleRectangle实现。这样展示抽象类如何强制子类实现特定方法,同时通过多态调用。 接下来是接口的例子,定义一个IWorker接口,包含Work方法,由EmployeeRobot类实现。这样可以展示接口如何实现多态,不同的类实现相同接口但行为不同。 在代码示例中,要确保语法正确,比如使用virtual、override关键字,抽象类接口的定义。同时,Main函数中创建对象并调用方法,展示多态的效果,比如将子类对象存储在基类或接口类型的变量中,调用方法时执行子类的实现。 还需要考虑用户可能的疑问,比如虚方法抽象方法的区别,接口抽象类的适用场景。因此,在解释部分需要简要说明这些点,帮助用户理解不同实现方式的适用情况。 最后,生成相关问题,引导用户深入思考,比如性能优化、设计模式应用等,这些问题应该与示例中的内容相关,并参考提供的引用资料。 现在检查代码是否正确:Animal基类的MakeSound标记为virtual,DogCat重写它;Shape是抽象类,有抽象方法;接口IWorker正确声明,实现类正确。Main函数中的调用是否展示了多态,比如将子类对象赋给基类数组,循环调用方法,确保输出不同的结果。 确保代码符合C#语法,比如分号、大括号,类方法定义正确。同时,注释要简洁,解释关键点,如“// 多态调用”来突出多态的应用。 总结:通过分步骤的代码示例,覆盖继承、虚方法、抽象类接口,展示多态的不同实现方式,并结合引用资料中的概念,确保回答准确且有帮助。</think>以下是一个结合C#继承多态特性的代码示例,包含虚方法、抽象类接口三种实现方式: ### 1. 基础继承与虚方法多态 ```csharp // 基类 public class Animal { public virtual void MakeSound() { Console.WriteLine("动物发出声音"); } } // 子类继承实现 public class Dog : Animal { public override void MakeSound() { Console.WriteLine("汪汪汪!"); } } public class Cat : Animal { public override void MakeSound() { Console.WriteLine("喵喵喵!"); } } // 使用示例 Animal[] animals = new Animal[] { new Dog(), new Cat() }; foreach (var animal in animals) { animal.MakeSound(); // 多态调用[^2] } ``` ### 2. 抽象类实现多态 ```csharp abstract class Shape { public abstract double CalculateArea(); // 抽象方法强制实现[^3] } class Circle : Shape { public double Radius { get; set; } public override double CalculateArea() { return Math.PI * Radius * Radius; } } class Rectangle : Shape { public double Width { get; set; } public double Height { get; set; } public override double CalculateArea() { return Width * Height; } } // 使用示例 Shape shape1 = new Circle { Radius = 5 }; Shape shape2 = new Rectangle { Width = 4, Height = 6 }; Console.WriteLine($"圆形面积: {shape1.CalculateArea()}"); Console.WriteLine($"矩形面积: {shape2.CalculateArea()}"); ``` ### 3. 接口多态实现 ```csharp interface IWorker { void Work(); // 接口定义契约[^1] } class Employee : IWorker { public void Work() { Console.WriteLine("员工在办公"); } } class Robot : IWorker { public void Work() { Console.WriteLine("机器人在生产"); } } // 使用示例 List<IWorker> workers = new List<IWorker> { new Employee(), new Robot() }; foreach (var worker in workers) { worker.Work(); // 统一接口调用 } ``` **关键特性说明:** 1. 虚方法(`virtual/override`):允许子类重写父类方法实现 2. 抽象类(`abstract`):强制子类实现特定方法,无法实例化 3. 接口(`interface`):定义行为契约,支持多重实现 4. 多态调用:通过基类/接口引用访问具体实现[^2]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值