jjjhkjhiu 2025-04-27 04:36 采纳率: 50%
浏览 12

面向对象c# .net,继承和多态

我是一个刚开始学习接触面向对象编程的学生,学了c#大概有几天,目前学到继承多态有个疑问。既然在向上转型(子类转为父类)时,变量的静态类型已经变成了父类,理论上就应该严格限制只能访问父类自身定义的成员,按照这种思路,子类新增的字段和功能在向上转型后,不应该再被访问到(这是我粗浅理解),然而,由于子类overide了父类的virtual属性,导致即使通过父类引用访问,看似访问的是重写后的版本,但是却间接操作了父类类型里本不应该有的成员(基类vehicle被改写后的属性其实是在操作自己派生类car类独有的私有字段_rpm) ,所以这种间接操作是否破坏了封装性?亦或者我对面向对象编程的理解上出现了问题?

using System.Buffers;
using System.Runtime.CompilerServices;
using System.Security.Cryptography.X509Certificates;

namespace OOP;

class Program
{
    static void Main(string[] args)
    {
        Vehicle car = new Car();
        car.Accelarate();//实际上间接操作的是子类的私有字段,站在vehicle类的角度看,这个字段不该存在啊.
        System.Console.WriteLine(car.Speed);//虽然是Vehicle类的属性,但实际上读取的也是子类私有字段,输出12.

    }


}
class Vehicle
{
    private int _speed;//基类speed字段
    public virtual int Speed { get { return _speed; } set { _speed = value; } }
    public virtual void Accelerate()//父类虚方法
    {
        Speed += 10;
    }
}

class Car : Vehicle
{
    public int _rpm;//子类独有的_rpm字段
    public override int Speed { get { return _rpm / 80; } set { _rpm = value; } }
    public override void Accelerate()//改写父类方法
    {
        _rpm += _rpm + 1000;
    }

}


  • 写回答

6条回答 默认 最新

  • 宝码香车 优质创作者: JavaScript技术领域 2025-04-27 07:48
    关注

    让【宝码香车】来帮你解答,本回答参考DeepSeek编写,并整理提供。
    如果还有疑问可以点击头像关注私信或评论。如果答案让您满意,请采纳、点赞、关注,非常感谢!

    关于C#继承和多态中封装性的理解

    你的问题非常好,涉及到面向对象编程中继承、多态和封装性这几个核心概念的关系。

    你的观察是正确的

    你注意到当子类Car重写父类VehicleSpeed属性和Accelerate()方法时,实际上是在操作子类特有的_rpm字段,而通过父类引用访问时,看似违反了"父类引用只能访问父类成员"的原则。

    这并不违反封装性

    这种现象实际上是多态的正常表现,并不违反封装性原则,原因如下:

    1. 多态是面向对象的核心特性:方法重写(override)本身就是设计用来改变父类行为的机制。父类定义了"可以做什么"(接口),子类定义了"如何做"(实现)。

    2. 封装性仍然保持

      • 父类并不知道子类的具体实现细节
      • 子类的_rpm字段仍然是私有的,外部无法直接访问
      • 所有操作都是通过父类定义的公共接口(SpeedAccelerate)进行的
    3. **里氏替换原则(LSP)**:子类应该能够替换父类而不影响程序的正确性。你的例子中,Car完全遵循了Vehicle的契约。

    你的理解偏差

    你的理解偏差在于将"变量静态类型限制"和"多态行为"对立起来了。实际上:

    • 静态类型限制:确实限制了你能调用的成员(只能调用父类中定义的成员)
    • 多态行为:决定了这些成员被调用时实际执行哪个版本的代码

    更准确的理解方式

    Vehicle car = new Car();
    car.Accelerate(); // 这里发生了:
    // 1. 编译器检查:Vehicle类是否有Accelerate方法?有 → 通过编译
    // 2. 运行时:实际调用的是Car类的Accelerate实现
    

    设计建议

    这种设计是合理的,但要注意:

    1. 子类重写方法时应该保持父类方法的语义不变
    2. 如果子类需要完全不同的行为,考虑使用抽象类或接口
    3. 避免在子类重写方法中引入与父类方法无关的副作用

    总结

    这不是封装性的破坏,而是多态性的体现。父类定义了"可以做什么",子类定义了"如何做",这正是面向对象编程的强大之处。你的例子展示了多态如何允许我们通过统一的接口操作不同的实现,这是OOP的核心价值之一。

    评论

报告相同问题?

问题事件

  • 修改了问题 4月27日
  • 创建了问题 4月27日