【问题标题】:Dynamic Polymorphism's weird output动态多态的奇怪输出
【发布时间】:2017-03-22 05:59:18
【问题描述】:

我无法理解输出。我有以下两个课程,

class A
{
    public int i = 1;

    public virtual void Print()
    {
        Console.WriteLine("I am A");
    } 
}

class B:A
{
    public int i =2 ; 

    public override void Print()
    {
        i++;
        Console.WriteLine("I am B");
    }

}

现在,当我运行以下代码时,

A a1 = new PolymorphismInDepth.B();
        a1.Print();
        Console.WriteLine(a1.i);

我得到以下输出,


我是B

1


为什么我得到 1?为什么不是 2?

【问题讨论】:

    标签: c# inheritance dynamic polymorphism


    【解决方案1】:

    基类对象a1 指向内存中的派生对象。因此a1.Print() 将调用方法引用,即B().Print(),但您无法使用此A().i 访问B().i

    你需要投射它:

    Console.WriteLine(((B)a1).i);
    

    您很困惑,因为您使用了相同的变量名。试试这个:

    class A
    {
        public int ai = 1;
    
        public virtual void Print()
        {
            Console.WriteLine("I am A");
        }
    }
    
    class B : A
    {
        public int bi = 2;
    
        public override void Print()
        {
            bi++;
            Console.WriteLine("I am B");
        }
    
    }
    
    static void Main(string[] args)
    {
        A a1 = new B();
        a1.Print();
        Console.WriteLine(a1.ai);
        Console.WriteLine(((B)a1).bi);
        Console.Read();
    }
    

    尝试像这样访问bi 应该会给你一个编译时错误:

    Console.WriteLine(a1.bi); //ERROR: 'A' does not contain a definition for 'bi'...
    

    更新:

    补充答案 - 也可以实现这样的实现,您可以覆盖基类成员变量的行为:

    class A
    {
        private int i = 1;
        public virtual int I
        {
            get { return i; }
        }
    
        public virtual void Print()
        {
            Console.WriteLine("I am A");
        }
    }
    
    class B : A
    {
        private int i = 2;
    
        public override int I
        {
            get { return i; }
        }
        public override void Print()
        {
            i++;
            Console.WriteLine("I am B");
        }
    
    }
    
    
    A a1 = new B();
    a1.Print();
    Console.WriteLine(a1.I);
    Console.WriteLine(((B)a1).I);
    

    输出:

    我是B

    3

    3

    【讨论】:

    • 请详细说明“您的 B().i 隐藏了基类成员 A().i”,使其清晰且具有描述性
    • 你可以更清楚地说,B.i 是一个新变量,与 A.i 无关。它恰好具有相同的名称(您通过重命名很好地解决了问题)。
    • @PeterA.Schneider - 我想了想,其实没那么简单。问题并没有因为名称相同而发生,问题是A 提供的接口在编译时无法访问B 中的项目。 OP 的假设是具有相同的变量名称将允许访问派生对象的变量 - 不一定与变量名称有关。
    • 好吧,“OP 的 [错误] 假设 [...] 具有相同的变量名将允许访问派生对象的变量”正是重点。变量完全不相关。他本可以将 B 的成员命名为 k 而无需更改语义(如您所演示的),但他认为该命名确实将两个不相关的成员神奇地连接起来。它没有。当然,“A提供的接口”可以访问B中的项目,可以通过调用a1.Print()简洁地演示。一个只是不能覆盖变量。 (虽然可以覆盖属性。)
    • @PeterA.Schneider 我认为 OP 知道这些变量是不相关的,因此 OP 期望输出变化。如果 OP 想要成员多态性,OP 可以标记 base i virtual。
    【解决方案2】:

    除了萨迪克所说的。如果您将您的类标记为公共并构建,您会看到编辑器正在为 B 类中的变量 i 指示某些内容。它表示您正在隐藏基成员 I,应该使用 new 关键字覆盖。

    所以,如果你删除 public int i =2 ;从 B 类中,当您修改基本变量时,您会得到 2 的输出。但是,如果您在 B 中声明 new i,那么您将在 B 中创建单独的 new i 范围。

    如果您将调试器放在Console.WriteLine(a1.ai); 行上,那么使用当前代码 它清楚地显示了两个 i 变量,一个值为 1,另一个值为 2。值 2 用于类型 B。因此,只有当您从 B 的实例中引用 i 时,您才会得到 2。

    希望这能消除疑虑。

    【讨论】:

      猜你喜欢
      • 2021-05-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多