C#继承中子类修改父类protected字段的逻辑疑问
C#继承中同名字段的隐藏问题解析
你遇到的问题核心是子类字段隐藏了父类的同名字段,这和方法的覆盖(override)逻辑完全不同,具体原因拆解如下:
1. 字段没有“覆盖”,只有“隐藏”
C#中,字段不支持像虚方法那样的覆盖机制。当子类定义了和父类同名的字段时,子类字段会隐藏父类的同名字段——相当于两个完全独立的字段,只是名字一样:
- 父类
Member的protected int annualFee是父类自己的字段,默认值为0(int类型默认值)。 - 子类
VIPMember的public int annualFee = 120000是子类自己的字段,初始值设为120000。
2. 子类方法中访问同名字段的默认行为
在子类的CalculateAnnualFee方法里,你写的annualFee = 1200 * 2 + 12 * 30;,默认访问的是子类自己的字段,而不是父类的。所以这行代码把子类的annualFee从120000改成了2760,但父类的annualFee始终没被赋值,还是默认的0。
3. 父类方法只能访问自己的字段
父类Member的ToString方法属于父类,它只能访问父类自己的annualFee字段,所以输出的是0,而不是子类字段的值。
4. 外部访问子类实例的字段时的行为
测试代码中myChildMember2.annualFee直接访问的是子类的字段,所以显示的是被CalculateAnnualFee修改后的2760,而不是初始的120000。
修正方案
如果你想让父类的ToString输出计算后的年费,同时保持子类对外暴露字段的需求,可以这么改:
方案1:移除子类的同名字段,直接使用父类字段
class VIPMember : Member { public VIPMember(string name, int memberId, int memberSince) : base (name, memberId, memberSince) { Console.WriteLine("Child constructor with 3 paramemters"); } public void CalculateAnnualFee() { annualFee = 1200 * 2 + 12 * 30; // 此时访问的是父类的protected字段 } // 如果需要对外公开父类的annualFee,用属性包装 public int AnnualFee => annualFee; }
方案2:明确区分父类和子类字段(不推荐,易混淆)
如果一定要保留子类的同名字段,需要在代码中明确指定访问父类还是子类的字段:
class VIPMember : Member { public VIPMember(string name, int memberId, int memberSince) : base (name, memberId, memberSince) { Console.WriteLine("Child constructor with 3 paramemters"); } public void CalculateAnnualFee() { base.annualFee = 1200 * 2 + 12 * 30; // 给父类字段赋值 this.annualFee = 120000; // 保留子类字段初始值 } public int annualFee = 120000; }
内容的提问来源于stack exchange,提问作者Jun
相关产品推荐
相关产品推荐

