[C#] ——多态和虚方法

[C#] ——多态和虚方法 今天只有一个核心搞懂 override 为什么不能漏。这是 C 转 C# 最隐蔽的坑。一、 虚方法 virtual —— 这块和 C 几乎一样// C class Animal { public: virtual void Speak() { cout ...; } // 标记可重写 }; // C# —— 关键字、含义都一样 class Animal { public virtual void Speak() Console.WriteLine(...); } virtual 「我这个方法允许子类重写」二、 重写 override —— 坑在这重点看2.1C 和 C# 的关键差异/ C基类 virtual 了子类同名函数【自动】多态 class Dog : public Animal { public: void Speak() { cout 汪; } // 加不加 override 都多态C11 的 override 只是可选校验 }; // C#子类必须【显式写 override】否则不参与多态 class Dog : Animal { public ovvride void speak() Console.WriteLine($汪汪汪); public void speak() Console.WriteLine($汪汪汪); //这是方法隐藏不是多态 }一句话记住C 是「默认多态override 可选」C# 是「override 必填不写就不多态」。2.2为什么 C# 这么设计C 那套「子类同名自动多态」有个经典 bug你基类没写 virtual子类碰巧写了个同名函数结果意外触发或没触发多态行为反直觉。C# 选择了显式安全想多态基类写 virtual子类写 override两边都要明说。少一个都不行。编译器帮你把关。四、 抽象类 abstract —— ≈ C 纯虚函数// C含纯虚函数 抽象类不可实例化 class Shape { public: virtual double Area() 0; // 纯虚 }; // C#abstract 关键字 abstract class Shape { public abstract double Area(); // 抽象方法无方法体子类必须 override public void Describe() Console.WriteLine($面积{Area():F2}); // 可含具体方法 }概念CC#抽象类含 0 的 classabstract class抽象方法virtual ... 0abstract ...;无方法体不可实例化是是new Shape() 编译错误子类必须实现是是必须 override4.1virtual vs abstract 选哪个基类有默认实现、子类可改可不改 → virtual基类不知道怎么实现、子类必须实现 → abstract这点 C C# 一致。五、 对照表维度CC#备注虚方法virtualvirtual一样重写同名即可override 可选必须 override⚠️ 核心差异方法隐藏隐式按静态类型new 显式声明C# 特有抽象类含 0abstract class语义一致抽象方法virtual ... 0abstract...;语义一致// Day04 练习多态与虚方法 // 核心坑C# 子类重写必须显式写 override否则是「方法隐藏 new」、不参与多态 using System; using System.Collections.Generic; // ---------- 1. 虚方法 virtual ---------- class Animal { public string Name { get; } public Animal(string name) Name name; // virtual标记此方法可被重写。C 也是 virtual几乎一样 public virtual void Speak() Console.WriteLine(${Name}: ...动物叫声); } // ---------- 2. 重写 override —— 多态的关键 ---------- class Dog : Animal { public Dog(string name) : base(name) { } // override必须显式写少了它就不是多态见下方 Puppy 反例 public override void Speak() Console.WriteLine(${Name}: 汪汪); } class Cat : Animal { public Cat(string name) : base(name) { } public override void Speak() Console.WriteLine(${Name}: 喵); } // ---------- 3. 反例方法隐藏 new不的多态 ---------- class Puppy : Dog { public Puppy(string name) : base(name) { } // 故意不写 override用 new「隐藏」基类方法 public new void Speak() Console.WriteLine(${Name}: 呜呜小狗奶音); } // ---------- 4. 抽象类 abstract ---------- // C 等价含纯虚函数 virtual ... 0 的 class不可实例化 abstract class Shape { public abstract double Area(); // 抽象方法无实现子类必须 override public void Describe() Console.WriteLine($面积 {Area():F2}); // 抽象类可含具体方法 } class Square : Shape { public double Side { get; } public Square(double side) Side side; public override double Area() Side * Side; // 必须实现抽象方法 } // ---------- 5. 主程序 ---------- class Program { static void Main() { // 多态基类引用装子类对象 ListAnimal zoo new() { new Dog(旺财), new Cat(咪咪), new Puppy(小黑) // Puppy 是 Dog 子类 }; Console.WriteLine( 动物园多态叫声 ); foreach (var a in zoo) { a.Speak(); // 同样 a.Speak()不同对象不同行为 多态 } // 踩坑Puppy 的 new 隐藏不参与多态 Console.WriteLine(\n override vs new 踩坑 ); Animal aPuppy new Puppy(小黑); // 基类引用指向 Puppy aPuppy.Speak(); // 输出汪汪而非呜呜 —— new 不多态沿继承链找到 Dog 的 override Console.WriteLine(只有用 Puppy 类型引用才听到奶音); Puppy p new Puppy(小黑); p.Speak(); // 编译期类型是 Puppy调用隐藏版本 → 呜呜 // 抽象类 Console.WriteLine(\n 抽象类 ); ListShape shapes new() { new Square(4), new Square(2.5) }; foreach (var s in shapes) { s.Describe(); // 具体方法内部多态调用 Area() } // Shape s new Shape(); // ❌ 编译错误抽象类不能实例化 } }