Как избежать наследования всех вещей из базового класса - PullRequest
1 голос
/ 10 октября 2009

Я думал о таком сценарии:

class Utopia => Базовый класс, который передает свои поля и методы производным классам.

class Watashi => Производный класс, производный от утопии и наследующий все

class Baka => Производный класс, наследует некоторые поля из утопии

Есть несколько типов выше, и тип Baka должен наследовать некоторые конкретные поля и методы, но как? Как я могу указать поля и методы, которые наследует только Бака, тогда как Ватаси наследует все от утопии.

Пример кода:

class Utopia {
   public string Moshi;

   [Exclude(ClassName("Baka"))]
   public string HaveIt;
}

class Baka : Utopia 
{
 // only Moshi appears here
 base.[Moshi]
}

class Watashi : Utopia 
{
  base.[Moshi][HaveIt];
}

Если я хочу использовать полиморфизм:

   Utopia _utopiaBaka = new Baka();
   _utop.[Moshi];

   Utopia _utopiaWatashi = new Watashi();
   _utopiaWatashi.[Moshi][HaveIt];

И, конечно, Framework также проверяет производные классы, являются ли они базовыми классами для других типов.

Ответы [ 7 ]

8 голосов
/ 10 октября 2009

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

Затем расширьте этот класс PartialUtopia, добавьте остальные методы и получите от него наследство Watashi.

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

1 голос
/ 10 октября 2009

Есть два разных понятия: интерфейсы и наследование. По сути, это два разных вопроса. Один из них «Как я хочу взаимодействовать с этим объектом?» (интерфейс). Второй: «Как этот объект работает внутри?» (Наследование).

В классических примерах ООП рассмотрим базовый класс:

class Shape {
    virtual void draw();
    virtual int size();
}

Это интерфейс, он определяет, как вы работаете с разными фигурами. Теперь рассмотрим это:

class Square : Shape {
    ...
}

class Circle : Shape {
    ...
}

Хотя интерфейсы для этих двух классов будут одинаковыми (draw () и size ()), реализации не будут иметь ничего общего. Действительно ли код рисования для круга вообще имеет отношение к коду рисования для квадрата? Нет, они просто имеют одинаковое имя и желаемый результат.

Причина, по которой я привожу это, состоит в том, что если вы хотите, чтобы некоторые классы наследовали некоторые члены других классов, то у вас может быть проблема, что вы путаете наследование с интерфейсами. AFAIK, C ++ не поддерживает интерфейсы (я, вероятно, ошибаюсь по этому поводу). Но вы могли бы подделать это с помощью «чисто виртуальных» классов (например, Shape выше).

class Shape {
    virtual void draw();
}

class EdgyShape : Shape {
    virtual int width();
    virtual int height();
}

class RoundyShape : Shape {
    virtual int radius();
}

Теперь у вас есть интерфейсы с иерархией, но нет реализации вообще.

class Circle : RoundyShape {
    ...
}

class Rectangle : EdgyShape {
    ...
}

class Square : Rectangle {
    ...
}

То есть, у Circle и Rectangle нет общего кода, а у Rectangle и Square нет. И все 3 используют один и тот же базовый интерфейс Shape с некоторыми дополнениями в зависимости от типа.

Может быть, это проливает свет на то, как реорганизовать классовую иерархию, чтобы вы могли лучше разделить их?

1 голос
/ 10 октября 2009

Что вы пытаетесь сделать конкретно? Если вас беспокоит подкласс, переопределяющий данную реализацию метода, вы всегда можете объявить метод sealed :

class FooBase
{
    sealed void Bar()
    {
        //base implementation
    }
}

class FooDerived
{
    void Bar()  //poof! compilation error
    {
        //never reached
    }
}

В качестве альтернативы вы можете иметь свой наследующий подкласс внутри сборки и не наследующий снаружи. Просто используйте protected internal.

1 голос
/ 10 октября 2009

То, что вы хотите сделать, полностью несовместимо с концепцией наследования в объектно-ориентированном программировании. Это все равно что спросить "Почему синий синий?" если бы синий не был синим, он не был бы синим.

Когда один класс (бака) наследует от другого (утопия), это означает (в ООП), что Бака может делать все, что может утопия - языки ООП предлагают функции, которые основаны на этом, и если бы вы были в состоянии переопределить, вы бы получили ужасные исключения .

Например, если у меня есть метод, который принимает класс типа Utopia в качестве параметра, как показано ниже:

public void TakesUtopia(Utopia utopia)
{
    utopia.BePerfect();
}

Мы также можем передавать классы типа Ватаси и типа Бака, потому что они оба наследуются от Утопии. Бака, наследуя утопию, гарантированно имеет реализацию метода BePerfect ()

Если бы у экземпляра Baka не было реализации, случилось бы что-то ужасное.

Чтобы продвинуться в этом - подумайте, что происходит, когда TakesUtopia полагается на поведение утопии. Например, утопия предоставляет свойство PriceOfHappiness.

public string TakesUtopia(Utopia utopia)
{
     if (utopia.PriceOfHappiness() > 100)
     {
          return "Can't buy happiness';
     }
}

При написании моего метода TakesUtopia, стоит ли ожидать написания кода, чтобы учесть вероятность того, что какой-либо метод внутри утопии не будет реализован? Что будут делать такие методы при вызове?

1 голос
/ 10 октября 2009

Я бы предложил исследовать различия между public , private и protected Похоже, это то, что вы ищете.

http://msdn.microsoft.com/en-us/library/ms173149.aspx

1 голос
/ 10 октября 2009

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

1 голос
/ 10 октября 2009

Это не то, как наследование работает в ООП. Бака наследует все от утопии, как Ватаси.

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