2014-01-07 7 views
5

Я пытаюсь понять, как наследование работает на C#. В принципе, у меня есть базовый класс Base, который имеет простую функцию sayIt. Функция использует свойство «i», которое переопределяется в подклассах. Здесь он переопределяется как 1 из 0. Когда я запускаю эту программу, я получаю «0» как вывод, а не «1», что я и ожидал (потому что в python я бы получил 1). Может ли кто-нибудь объяснить, почему, и что более важно, является ли это шаблоном, который поддерживается на C#?Недоразумение наследования в C#

class Program 
{ 
    static void Main(string[] args) 
    { 
     Derived d = new Derived(); 
     Console.WriteLine(d.sayIt()); 
     Console.ReadLine(); 
    } 
} 

class Base 
{ 
    int _i = 0; 
    public int i 
    { 
     get { return _i; } 

    } 

    public String sayIt() 
    { 
     return Convert.ToString(this.i); 
    } 
} 

class Derived : Base 
{ 
    int _i = 1; 
    public new int i 
    { 
     get { return _i; } 
    } 
} 
+0

см http://en.wikipedia.org/wiki/Object_slicing, это не то, что вы хотите сделать без веской причины. – Yaur

+0

Я ничего не добавлю к базе: я просто переопределяю некоторые вещи, поэтому я не открываю себя для нарезки. – guyrt

ответ

8
  1. Отметить собственность как virtual в Base класса

  2. Заменить new с override рядом с отелем в Derived класса.

1. необходимо, потому что члены не являются виртуальными в C# по умолчанию. и 2. необходимо, потому что с помощью new будет разорвать разрешающий проход virtual, что не то, что вы хотите.

Существует хорошая статья о new и override на MSDN: Knowing When to Use Override and New Keywords (C# Programming Guide).

override модификатор расширяет метод базового класса, и модификатор new скрывает ее.

+0

Когда вы создаете 'Derived', есть ли две копии' _i' или нет? 'sayIt', очевидно, вызывает свойство' i' в классе, в котором он определен ('Base') (потому что он не виртуальный), но это не объясняет, почему само свойство вытягивает' _i' из того же класса если не секретно две копии '_i', которая задает вопрос, как рассказать друг другу? – mpen

+0

Оба поля '_i' существуют. и 'sayIt' не тянет' _i' напрямую: он вытаскивает свойство 'i', которое является' virtual', поэтому 'Derived.i' берется и называет' '_' '. – MarcinJuraszek

+0

QUIT приятное объяснение. +1. –

3

Для того, чтобы иметь функцию, которая может быть переопределен в производном типа вам нужно, чтобы сделать его virtual

public virtual int i 
{ 
    get { return _i; } 
} 

Тогда в производный тип можно переопределить поведение с override ключевого слова

public override int i 
{ 
    get { return _i; } 
} 
3

В C# у вас есть возможность НЕ разрешить полное полиморфное/наследование поведения в ваших классах.

Для того, чтобы получить ожидаемый результат ваш код должен выглядеть следующим образом: (не проверял)

class Base 
{ 
    int _i = 0; 
    public virtual int i 
    { 
     get { return _i; } 

    } 

    public String sayIt() 
    { 
     return Convert.ToString(this.i); 
    } 
} 

class Derived : Base 
{ 
    int _i = 1; 
    public override int i 
    { 
     get { return _i; } 
    } 
} 

Теперь вы говорите C# переводчику, что я есть «виртуальный» или базовое представление может быть переопределяется дочерними классами.

В вашем старом коде вы вызываете sayIt(), который находится в Base(). Поскольку i не является виртуальным, он не ищет дочернюю оперутацию, которая была переопределена.

В основном в C#, чтобы иметь правильное наследование и полиморфизм, ваш код нуждается в явном объявлении в синтаксисе с использованием «виртуального», затем «переопределить».

0

Путаница заключается в том, что вы технически используете имя, скрывающееся в производном классе, вместо того, чтобы переопределять поведение базового класса. При использовании скрытия элемента тип, на который вы ссылаетесь, определяет, какой метод фактически работает, поскольку оба существуют. Новый позволяет указать, что вы намерены «скрыть» базовую реализацию для тех, кто специально вызывает ваш метод по назначенному типу.Чтобы проиллюстрировать:

class Program 
    { 
     static void Main(string[] args) 
     { 
      //both 'i' properties exist 
      Derived d = new Derived(); 

      Console.WriteLine(d.i); // uses the 'i' for this type 
      Console.WriteLine(((Base)d).i); // uses the 'i' for this type 
      Console.ReadLine(); 
     } 
    } 

class Base 
{ 
    int _i = 0; 
    public int i 
    { 
     get { return _i; } 

    } 

    public String sayIt() 
    { 
     //this class and this method doesn't realize the derived class has hid this.i 
     return Convert.ToString(this.i); 
    } 
} 

class Derived : Base 
{ 
    int _i = 1; 
    public new int i 
    { 
     get { return _i; } 
    } 
} 

Это то, что вы хотите, я считаю, для достижения картины.

class Base 
{ 
    int _i = 0; 
    public virtual int i 
    { 
     get { return _i; } 

    } 

    public String sayIt() 
    { 
     return Convert.ToString(this.i); 
    } 
} 

class Derived : Base 
{ 
    int _i = 1; 
    public override int i 
    { 
     get { return _i; } 
    } 
} 

Надеюсь, что это поможет.

-DW

0

Как уже упоминалось изменить свойство я к виртуальному в Базе и использовать переопределение свойства в производном классе. Ниже приведен пример для вывода для каждого случая, чтобы лучше понять его. Вы можете видеть, что вы получите другой результат, для варианта 2.

class Base 
{ 
    int _i = 0; 
    public virtual int i 
    { 
     get { return _i; } 
    } 

    public String sayIt() 
    { 
     return Convert.ToString(this.i); 
    } 
} 

class Derived : Base 
{ 
    int _i = 1; 
    public override int i 
    { 
     get { return _i; } 
    } 
} 

Вы можете создать экземпляр кода в 3 различными способами:

// Option 1 
Base a = new Base(); 
Console.WriteLine(a.i); 
// Output using virtual/override --> 0 
// Output using new --> 0 


// Option 2 
Base b = new Derived(); 
Console.WriteLine(b.i); 
// Output using virtual/override --> 1 
// Output using new --> 0 

// Option 3 
Derived c = new Derived(); 
Console.WriteLine(c.i); 
// Output using virtual/override --> 1 
// Output using new --> 1 

// Option 2 
// Derived d = new Base(); 
// Console.WriteLine(d.i); 
// This won't obviously compile 
Смежные вопросы