Наследование в c # вопросе - PullRequest
0 голосов
/ 16 августа 2010

У меня есть элементарный вопрос о наследовании в C #.

У меня есть два класса. Я хочу, чтобы дочерний класс наследовал все члены базового класса (например, x и y), но, похоже, что он использует наследование, я должен инициализировать базовый конструктор. Если я определю другие x и y в дочернем классе, чтобы потом позже инициализировать базовый конструктор, в чем же смысл наследования? И в чем решение?

Другой вопрос заключается в том, что у меня есть два метода с одинаковой сигнатурой в базовом и дочернем классе, и мне нужно использовать оба. Что я могу сделать?

class Base
{
    int x;
    int  y;
    string name;

    public Base(int i,int j)
    {
        x = i;
        y = j;
        name="s";
    }
}

class Child
{
    public Base()
    {

    }
}

Ответы [ 4 ]

2 голосов
/ 16 августа 2010

Ваши вопросы не очень понятны, и код недействителен [теперь исправлен редактором], но я собираюсь ответить на то, что, по-вашему, вы спрашиваете.

Чтобы инициализировать поля базового класса в производном классе, вы должны вызвать базовый конструктор из конструктора вашего производного класса:

class Base
{
    private int x;
    private int y;

    // ...

    public Base(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
}

// option 1, pass in values as parameters to constructor:
class Child1
{
    public Child(int x, int y)
        : base(x, y) // this passes the values up to the base constructor
    {
    }
}

// option 2, pass literals to the base constructor:
class Child2
{
    public Child()
        : base(3, 4) // this passes the literal values 3 and 4 to the base constructor
    {
    }
}

// elsewhere

var child1 = new Child1(1, 2); // child1.x = 1, child1.y = 2
var child2 = new Child2(); // child2.x = 3, child2.y = 4

Теперь о вашем втором вопросе о наличии метода в производном классе с тем же именем. Если вы хотите переопределить поведение метода, вы должны сделать его виртуальным в базовом классе и переопределить его в производном классе, что вы можете увидеть из метода под названием SomeAction в этом примере:

class Base
{
    public virtual void SomeAction()
    {
        Console.Out.WriteLine("Base.SomeAction");
    }

    public void DifferentAction()
    {
        Console.Out.WriteLine("Base.DifferentAction");
    }
}

class Derived
{
    // this is a normal override
    public override void SomeAction()
    {
        Console.Out.WriteLine("Derivde.SomeAction");
    }

    // this is an advanced technique which you should try to avoid in most cases
    public new void DifferentAcion()
    {
        Console.Out.WriteLine("Derived.DifferentAction");
    }
}

// elsewhere
var base = new Base();
base.SomeAction(); // prints Base.SomeAction
base.DifferentAction(); // prints Base.DifferentAction

var derived = new Derived();
derived.SomeAction(); // prints Derived.SomeAction
derived.DifferentAction(); // prints Derived.DifferentAction

((Base) derived).SomeAction(); // prints Derived.SomeAction
((Base) derived).DifferentAction(); // prints Base.DifferentAction

Если метод переопределен, то новое поведение будет отображаться независимо от того, ссылаетесь ли вы на него как на базовый тип или на производный тип.

(Если вы используете ключевое слово new или ничего не ставите, то создается новая цепочка наследования, и поведение будет зависеть от того, ссылаетесь ли вы на объект как на базовый тип или производный тип. Вы можете увидеть это в последних двух вызовах в приведенном выше коде: для переопределенного метода используется производное поведение, но для метода, в котором использовался 'new', оригинальное поведение проявляется, когда объект обрабатывается как Base.)

0 голосов
/ 16 августа 2010

Конструктор базового класса всегда вызывается при создании экземпляра производного класса. Если базовый класс имеет конструктор по умолчанию, это будет вызов, если вы пропустите явный вызов конструктора базового класса.

* 1005 Е.Г. *

class Base
{
  int x;
  int y;

  //default constructor
  public Base()
  {
     x = -1;
     y = -1;
  }

  public Base(int x, int y)
  {
     this.x = x;
     this.y = y;
  }
}

class Derived
{
   public Derived()
   {
   }
}

это скомпилирует и установит поля экземпляра производного в -1 при создании производного объекта. Однако если вы опустите конструктор по умолчанию, вы получите ошибку компиляции, подобную той, которую вы описали. Теперь компилятор не способен автоматически генерировать вызов базового конструктора. Я бы знал, какие параметры вызвать с

base(x=??,y=??)

Как правило, у вас должны быть открытые поля / свойства с одним и тем же именем, объявленными несколько раз, это почти всегда сильный запах проекта. Если базовый класс имеет защищенное, внутреннее или открытое поле / свойство, то же относится и к производному классу (у внутреннего есть несколько странных случаев). Для методов вы можете скрыть реализацию mthod базового класса или переопределить его. Последнее является более распространенным и требует, чтобы базовое определение было абстрактным или виртуальным. например,

//this requires Base to be declared abstract as well
public abstract void AbstractMethod(); 
public virtual void VirtualMethod(){}

, что позволяет писать следующим образом в классе DErived

public override void AbstractMethod(){}
public override void VirtualMethod(){}

Если вам нужно скрыть метод, вы можете сделать это, хотя это обычно не рекомендуется (см. Ниже, почему) если вы просто повторно объявите метод, компилятор выдаст вам предупреждение, но вы можете использовать new, чтобы сообщить компилятору, что вы действительно хотите скрыть метод, он будет выглядеть следующим образом:

публичный новый void SomeHiddenMethod () {}

как бы то ни было это (потенциально) очень сильно влияет на использование объектов этого типа

public void SomeMEthod(Derived d)
{
  //this calls the implementation in Derived
  d.SomeHiddenMethod();
  Base b = d;
  //this calls the implementation in Base
  b.SomeHiddenMethod(); 
}

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

И последнее замечание о наследовании, которое вы должны избегать наследования для функциональности, короче говоря, это просто потому, что вам нужны одинаковые функциональные возможности в двух (не связанных) классах, вы не должны создавать базовый класс для хранения этой функциональности, скорее вы должны создать третий класс, и инъекция, и экземпляр этого класса (или аналогичные подходы), и вы должны много думать о принципе замены Лискова при разработке открытого интерфейса класса, когда он не запечатан.

0 голосов
/ 16 августа 2010

Не определяйте x и y в дочернем классе. Они уже там, если Child наследует от Base.

0 голосов
/ 16 августа 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...