Следует ли удалить наследование (неинтерфейсных типов) из языков программирования?

Это довольно спорная тема, и прежде чем сказать «нет», действительно ли она действительно нужна?

Я занимаюсь программированием около 10 лет, и я не могу честно сказать, что могу вспомнить время, когда наследование решило проблему, которая не могла быть решена другим способом. С другой стороны, я могу вспомнить много раз, когда я использовал наследование, потому что я чувствовал, что должен, или потому что я думал, что был умен и в итоге заплатил за это.

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

Единственное, что я хочу сделать, это то, что мы по-прежнему разрешаем наследование интерфейсов.

(Обновить)

Давайте приведем пример того, почему это необходимо, вместо того, чтобы говорить «иногда это просто необходимо». Это действительно не помогает вообще. Где ваше доказательство?

(Пример обновления кода 2)

Вот классический пример формы, более мощный и более явный IMO, без наследования. В реальном мире почти никогда не бывает так, чтобы что-то действительно "являлось" чем-то другим. Почти всегда «Реализуется в терминах» является более точным.

public interface IShape
{
    void Draw();
}

public class BasicShape : IShape
{
    public void Draw()
    {
        // All shapes in this system have a dot in the middle except squares.
        DrawDotInMiddle();
    }
}

public class Circle : IShape
{
    private BasicShape _basicShape;

    public void Draw()
    {
        // Draw the circle part
        DrawCircle();
        _basicShape.Draw();
    }
}

public class Square : IShape
{
    private BasicShape _basicShape;

    public void Draw()
    {
        // Draw the circle part
        DrawSquare();
    }
}
+1 в ожидании удара, который ты собираешься взять за это. :)
MusiGenesis 11.12.2008 23:15:56
Только для правильного использования, не следует ли объявлять ваш приватный _basicShape как IShape, а не как BasicShape, так что если вам нужно изменить «базовую форму», вы можете без необходимости снова касаться кода форм.
David 12.12.2008 16:15:34
20 ОТВЕТОВ
РЕШЕНИЕ

Я писал об этом как о странной идее некоторое время назад.

Я не думаю, что это должно быть удалено, но я думаю, что классы должны быть запечатаны по умолчанию, чтобы препятствовать наследованию, когда это не подходит. Это мощный инструмент, который есть в наличии, но он похож на цепную пилу - вы действительно не хотите использовать его, если это не идеальный инструмент для работы. В противном случае вы можете начать терять конечности.

Это потенциальные языковые функции, такие как дополнения, которые облегчат жизнь без IMO.

20
11.12.2008 23:18:31
OMG Джон, я не могу поверить, что я действительно должен не согласиться с одним из ваших ответов! Наследование является основополагающим для объектно-ориентированного программирования, без него у вас есть только объектно-ориентированное программирование, которое не так эффективно. Говорить всем будущим разработчикам, что они не могут быть выведены из вашего класса, греховно ...
Steven A. Lowe 15.12.2008 05:29:55
@ Стивен: В то время как я считаю, что позволить людям извлекать уроки из вашего класса без вашей подготовки к нему (что требует много работы) гораздо опаснее. Джош Блох объясняет это лучше, чем я - см. Соответствующий пункт в Effective Java, 2-е издание.
Jon Skeet 15.12.2008 06:48:44
@Jon: проблема не в том, что наследование существует, проблема в том, что оно существует без множественного наследования, что устраняет необходимость в «корневых иерархиях», и поэтому вы почти никогда не сталкиваетесь с этими проблемами, которые вы иллюстрируете ... Хотя я согласен с ваш подход «запечатан по умолчанию» ...
Thomas Hansen 19.12.2008 19:53:32

Нет. Иногда тебе нужно наследство. И в те времена, когда вы не ... не используйте его. Вы всегда можете «просто» использовать интерфейсы (на тех языках, на которых они есть), а ADP без данных работают как интерфейсы на тех языках, где их нет. Но я не вижу причин удалять то, что иногда является необходимой функцией, просто потому, что вы чувствуете, что она не всегда нужна.

2
11.12.2008 23:16:30
Покажите мне один случай, когда это абсолютно необходимо.
John Sonmez 11.12.2008 23:18:32
Очевидно, что это никогда не «абсолютно» необходимо - существует полный язык программирования Тьюринга, который не имеет наследования. Или классы. Или объекты. Или встроенные петли. Независимо от того, нужно что-то или нет, это субъективно, и если вы действительно ненавидите какую-то функцию, вы найдете способ обойти это.
Steve Jessop 11.12.2008 23:51:54

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

2
11.12.2008 23:17:43

В большинстве случаев я выбираю базовый класс вместо интерфейса только потому, что у меня есть некоторые стандартные функции. в C # я теперь могу использовать методы расширения для достижения этой цели, но в нескольких ситуациях это все еще не достигает того же самого.

2
11.12.2008 23:18:31

Наследование может быть весьма полезным в ситуациях, когда в вашем базовом классе есть несколько методов с одинаковой реализацией для каждого производного класса, чтобы избавить каждый отдельный производный класс от необходимости реализовывать стандартный код. StreamНапример, класс .NET, который определяет следующие методы:

public virtual int Read(byte[] buffer, int index, int count)
{
}

public int ReadByte()
{
    // note: this is only an approximation to the real implementation
    var buffer = new byte[1];
    if (this.Read(buffer, 0, 1) == 1)
    {
        return buffer[0];
    }

    return -1;
}

Поскольку наследование доступно, базовый класс может реализовать ReadByteметод для всех реализаций, не беспокоясь об этом. В классе есть ряд других подобных методов, которые имеют стандартные или фиксированные реализации. Таким образом, в такой ситуации это очень ценно по сравнению с интерфейсом, в котором вы можете либо сделать так, чтобы все заново реализовали все, либо создать StreamUtilкласс типов, который они могут вызывать (yuk!).

Чтобы уточнить, с наследованием все, что мне нужно написать, чтобы создать DerivedStreamкласс, это что-то вроде:

public class DerivedStream : Stream
{
    public override int Read(byte[] buffer, int index, int count)
    {
        // my read implementation
    }
}

Принимая во внимание, что если мы используем интерфейсы и реализацию методов по умолчанию, StreamUtilя должен написать еще немного кода:

public class DerivedStream : IStream
{
    public int Read(byte[] buffer, int index, int count)
    {
        // my read implementation
    }

    public int ReadByte()
    {
        return StreamUtil.ReadByte(this);
    }
}

}

Так что это не намного больше кода, но умножьте это на несколько методов в классе, и это просто ненужные вещи, которые компилятор может обработать вместо этого. Зачем делать вещи более болезненными для реализации, чем необходимо? Я не думаю, что наследование - это начало и конец, но оно может быть очень полезным при правильном использовании.

10
11.12.2008 23:42:07
Как насчет класса, который наследовал бы от Stream вместо наследования от IStream и содержал экземпляр DefaultStream. Для своего метода ReadByte он вызывает DefaultStream.ReadByte ().
John Sonmez 11.12.2008 23:27:34
Это эффективно, что я сказал с классом StreamUtil. Конечно, это можно сделать, но почему вы хотите разделить реализацию на две части? И даже в этом случае производный класс должен написать прототипы и сквозные методы. Наследование в этом случае просто чище.
Greg Beech 11.12.2008 23:35:39
На мой взгляд, дополнительный код для переноса методов делегирования более понятен, чем классы, имеющие методы, которые не определены в классе. Немного дополнительного стандартного кода, но гораздо более конкретное намерение. Это очень ясно, что происходит, когда вы делегируете, но наследование не всегда.
John Sonmez 11.12.2008 23:40:17
Вы можете сказать то же самое об итераторах (yield return) - написание конечного автомата вручную делает более понятным, как работает итерация, поскольку вы даже не можете увидеть сгенерированный код, если не разберете сборку, но действительно хотите написать все этот код котельной плиты?
Greg Beech 11.12.2008 23:46:29
Этот пример как раз для чего нужны миксины. Одна из вещей, которую делают миксины, - это «расширение интерфейса», при котором вы реализуете небольшой интерфейс, и миксин заполняет его до большего, более удобного интерфейса. Я бы согласился, что языкам нужны миксины, но это не обязательно означает, что им нужно наследование.
Steve Jessop 11.12.2008 23:48:26

Моей первоначальной мыслью было: «Ты сумасшедший. Но, подумав немного, я с вами согласен. Я не говорю о полном удалении наследования классов (например, абстрактные классы с частичной реализацией могут быть полезны), но я часто наследовал (предназначенный для каламбура) плохо написанный ОО-код с многоуровневым наследованием классов, который ничего не добавил, кроме bloat, к код.

1
11.12.2008 23:26:31

Для производственного кода я почти никогда не использую наследование. Я использую интерфейсы для всего (это помогает в тестировании и улучшает читабельность, т.е. вы можете просто посмотреть на интерфейс, чтобы прочитать общедоступные методы и посмотреть, что происходит из-за хорошо названных методов и имен классов). Практически единственный раз, когда я бы использовал наследование, было бы потому, что этого требует сторонняя библиотека. Используя интерфейсы, я получил бы тот же эффект, но я бы имитировал наследование, используя «делегирование».

Для меня это не только более читабельно, но и гораздо более тестируемо, а также значительно упрощает рефакторинг.

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

Поэтому я, вероятно, не избавился бы от этого, но я решил не использовать его как можно чаще по причинам, указанным выше.

4
11.12.2008 23:43:40

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

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

1
11.12.2008 23:43:29

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

Давайте возьмем мой мир на данный момент, который в основном разрабатывается на C #.

Чтобы Microsoft отказалась от наследования на основе классов, им пришлось бы встроить гораздо более мощную поддержку обработки интерфейсов. Такие вещи, как агрегация, где мне нужно добавить много кода, просто чтобы подключить интерфейс к внутреннему объекту. Это действительно должно быть сделано в любом случае, но будет требованием в таком случае.

Другими словами, следующий код:

public interface IPerson { ... }
public interface IEmployee : IPerson { ... }
public class Employee : IEmployee
{
    private Person _Person;
    ...

    public String FirstName
    {
        get { return _Person.FirstName; }
        set { _Person.FirstName = value; }
    }
}

По сути, это должно быть намного короче, иначе у меня было бы много таких свойств, чтобы мой класс подражал человеку достаточно хорошо, что-то вроде этого:

public class Employee : IEmployee
{
    private Person _Person implements IPerson;
    ...
}

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

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

Кроме того, вы бы удалили такие вещи, как видимость. Интерфейс на самом деле просто имеет две настройки видимости: там и не там. В некоторых случаях вы, я думаю, будете вынуждены предоставить больше внутренних данных просто для того, чтобы кто-то еще мог легче использовать ваш класс.

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

Мой самый большой вопрос заключается в том, какой конкретно смысл будет удалять такую ​​функциональность, даже если в качестве примера планируется построить D #, новый язык, такой как C #, но без наследования на основе классов. Другими словами, даже если вы планируете создать совершенно новый язык, я все еще не совсем уверен, какой будет конечная цель.

Является ли целью удалить что-то, чем можно злоупотреблять, если не в правильных руках? Если это так, у меня есть список длиной в милю для различных языков программирования, которые я действительно хотел бы сначала посмотреть на адреса.

В верхней части этого списка: ключевое слово with в Delphi. Это ключевое слово не просто стреляет себе в ногу, это похоже на то, как компилятор покупает ружье, приходит к вам домой и целится в вас.

Лично мне нравится наследование на основе классов. Конечно, вы можете написать себе в угол. Но мы все можем сделать это. Уберите наследственное наследие, я просто найду новый способ выстрелить себе в ногу.

Теперь, где я положил этот дробовик ...

5
11.12.2008 23:53:18

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

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

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

Это допускает злоупотребления? Конечно, это так. Я часто вижу вопросы, спрашивающие, как разработчик может наследовать от класса, но скрывать метод, потому что этот метод не должен существовать в подклассе. Этот человек явно упускает из виду наследство, и вместо этого следует указать на делегирование.

Я не использую наследование, потому что оно необходимо, я использую его, потому что иногда это лучший инструмент для работы.

1
12.12.2008 00:06:06

Конечно, вы можете писать великолепные программы счастливо без объектов и наследования; функциональные программисты делают это постоянно. Но давайте не будем торопиться. Всем, кто интересуется этой темой, следует ознакомиться со слайдами из приглашенной лекции Ксавьера Леруа о классах и модулях в Objective Caml . Ксавье делает прекрасную работу, рассказывая о том, что наследование хорошо, а что нет в контексте различных видов эволюции программного обеспечения .

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

Я также напомню спрашивающему о «убийственном приложении» для наследования: инструментарий GUI. Хорошо разработанный инструментарий (если вы можете его найти) позволяет очень легко добавлять новые виды графических виджетов взаимодействия.

Сказав все это, я думаю, что наследование имеет врожденные недостатки (логика вашей программы размазана по большому набору классов) и что она должна использоваться редко и только опытными специалистами . Человек, получивший степень бакалавра в области компьютерных наук, почти ничего не знает о наследовании - таким людям должно быть разрешено наследовать от других нуждающихся классов, но никогда не следует писать код, который наследуют другие программисты. Эта работа должна быть зарезервирована для главных программистов, которые действительно знают, что они делают. И они должны делать это неохотно!

Для интересного решения подобных проблем с использованием совершенно другого механизма, люди могут захотеть проверить классы типа Haskell .

6
12.12.2008 06:31:19
Вы не можете сделать настоящий упс без наследства ИМО.
Spikolynn 5.03.2009 09:50:58
Прочтите о себе ( research.sun.com/self/papers/self-power.html ) и посмотрите, думаете ли вы так до сих пор.
Norman Ramsey 6.03.2009 21:53:41

Я думаю, я должен играть адвоката дьявола. Если бы у нас не было наследования, мы бы не смогли наследовать абстрактные классы, использующие шаблонный шаблон. Есть много примеров, когда это используется в таких средах, как .NET и Java. Поток в Java является таким примером:

// Alternative 1:
public class MyThread extends Thread {

    // Abstract method to implement from Thread
    // aka. "template method" (GoF design pattern)
    public void run() {
        // ...
    }
}

// Usage:
MyThread t = new MyThread();
t.start();

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

// Alternative 2:
public class MyThread implements Runnable {
    // Method to implement from Runnable:
    public void run() {
        // ...
    }
}

// Usage:
MyThread m = new MyThread();
Thread t = new Thread(m);
t.start();
// …or if you have a curious perversion towards one-liners
Thread t = new Thread(new MyThread());
t.start();

Сняв шляпу защитника моего дьявола, я полагаю, вы могли бы утверждать, что выгода во второй реализации - это внедрение зависимостей или разделение проблем, которые помогают разрабатывать тестируемые классы. В зависимости от вашего определения, что такое интерфейс (я слышал, по крайней мере, три), абстрактный класс может рассматриваться как интерфейс.

3
12.12.2008 06:57:02

Вот хороший вид на тему:

IS-STRICTLY-EQUIVALENT-TO-A от Ред Брейтуэйт

1
12.12.2008 12:11:33

Действительно ли наследство необходимо? Зависит от того, что вы подразумеваете под «действительно». Вы можете вернуться к перфокартам или теоретически переключить тумблеры, но это ужасный способ разработки программного обеспечения.

Да, в процедурных языках наследование классов - это определенное благо. Это дает вам возможность элегантно организовать ваш код в определенных обстоятельствах. Его не следует использовать чрезмерно, так как не следует злоупотреблять любой другой функцией.

Например, возьмем случай дигиарности в этой теме. Он / она использует интерфейсы почти для всего, что так же плохо, как (возможно, и хуже) с использованием большого количества наследования.

Некоторые из его пунктов:

это помогает с тестированием и улучшает читабельность

Это не делает ни то, ни другое. На самом деле вы никогда не тестируете интерфейс, вы всегда тестируете объект, то есть экземпляр класса. А необходимость взглянуть на совершенно другой фрагмент кода помогает понять структуру класса? Я так не думаю.

То же самое касается глубокой иерархии наследования. Вы в идеале хотите посмотреть только в одном месте.

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

Делегирование - очень хорошая идея, и ее часто следует использовать вместо наследования (например, шаблон «Стратегия» предназначен именно для этого). Но интерфейсы не имеют никакого отношения к делегированию, потому что вы не можете указать какое-либо поведение в интерфейсе.

также делает рефакторинг намного проще.

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

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

1
12.12.2008 12:38:42

Я хотел бы, чтобы языки предоставили некоторые механизмы, чтобы было проще делегировать переменным-членам. Например, предположим, что интерфейс I имеет 10 методов, а класс C1 реализует этот интерфейс. Предположим, я хочу реализовать класс C2, который похож на C1, но с переопределенным методом m1 (). Без использования наследования я бы сделал это следующим образом (на Java):

public class C2 implements I {
    private I c1;

    public C2() {
       c1 = new C1();
    }

    public void m1() {
        // This is the method C2 is overriding.
    }

    public void m2() {
        c1.m2();
    }

    public void m3() {
        c1.m3();
    }

    ...

    public void m10() {
        c1.m10();
    }
}

Другими словами, я должен явно написать код, чтобы делегировать поведение методов m2..m10 переменной-члену m1. Это немного боли. Это также загромождает код, так что реальную логику в классе C2 сложнее увидеть. Это также означает, что всякий раз, когда новые методы добавляются в интерфейс I, я должен явно добавлять больше кода в C1, чтобы делегировать эти новые методы в C1.

Я хотел бы, чтобы языки позволили мне сказать: C1 реализует I, но если в C1 отсутствует какой-либо метод из I, автоматически делегируется переменной-члену c1. Это сократило бы размер С1 до

public class C2 implements I(delegate to c1) {
    private I c1;

    public C2() {
       c1 = new C1();
    }

    public void m1() {
        // This is the method C2 is overriding.
    }
}

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

Вот статья в блоге, которую я написал об автоматическом делегировании.

6
19.12.2008 19:45:52

Если существует каркасный класс, который делает почти точно то, что вам нужно, но определенная функция его интерфейса генерирует исключение NotSupported или по какой-то другой причине вы хотите переопределить только один метод, чтобы сделать что-то конкретное для вашей реализации, гораздо проще написать подкласс и переопределить этот один метод, вместо того, чтобы писать новый класс и писать сквозные переходы для каждого из 27 других методов в классе.

Аналогично, как насчет Java, например, где каждый объект наследуется от Object, и, следовательно, автоматически имеет реализации equals, hashcode и т. Д. Мне не нужно их повторно реализовывать, и это «просто работает», когда я хочу использовать объект как ключ в хеш-таблице. Мне не нужно писать Hashtable.hashcode(Object o)метод по умолчанию для метода, который, откровенно говоря, кажется, что он удаляется от ориентации объекта.

1
12.12.2008 14:41:52

Нужен? Нет. Вы можете написать любую программу на C, например, которая не имеет какого-либо вида наследования или объектов. Вы могли бы написать это на ассемблере, хотя это было бы менее переносимо. Вы могли бы написать это на машине Тьюринга и сделать так, чтобы она имитировалась. Кто-то разработал компьютерный язык только с одной инструкцией (что-то вроде вычитания и ветвления, если не ноль), и вы могли бы написать свою программу на этом.

Итак, если вы собираетесь спросить, нужна ли данная языковая функция (например, наследование, или объекты, или рекурсия, или функции), ответ - нет. (Существуют исключения - вы должны иметь возможность зацикливаться и делать что-то условно, хотя они не должны поддерживаться как явные понятия в языке.)

Поэтому я считаю такие вопросы бесполезными.

Такие вопросы, как «Когда мы должны использовать наследование» или «Когда мы не должны», гораздо более полезны.

3
12.12.2008 15:12:56
Я не согласен. Вопрос ясен, и «Необходим» означает: «Делает ли это вашу программу проще в написании, короче и элегантнее?»
Erik Alapää 3.05.2017 05:36:14

Получайте удовольствие от реализации ISystemObject на всех ваших классах, чтобы у вас был доступ к ToString () и GetHashcode ().

Кроме того, удачи с интерфейсом ISystemWebUIPage.

Если вам не нравится наследование, я предлагаю прекратить использование .NET все вместе. Существует слишком много сценариев, в которых это экономит время (см. СУХОЙ: не повторяйте себя).

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

Я предпочитаю интерфейсы, но они не серебряная пуля.

5
8.01.2009 05:57:40

Вопрос заключается в том, следует ли удалить наследование (неинтерфейсных типов) из языков программирования?

Я говорю «нет», так как это сломает чертовски много существующего кода.

Кроме того, вы должны использовать наследование, кроме наследования интерфейсов? Я в основном программист на C ++ и придерживаюсь строгой объектной модели множественного наследования интерфейсов, за которой следует цепочка одиночного наследования классов . Конкретные классы являются «секретом» компонента и его друзей, поэтому то, что происходит, не имеет никакого отношения к делу.

Чтобы помочь реализовать интерфейсы, я использую шаблонные миксины. Это позволяет конструктору интерфейса предоставлять фрагменты кода, чтобы помочь реализовать интерфейс для распространенных сценариев. Как разработчик компонентов, я чувствую, что могу пойти за покупками, чтобы получить многократно используемые биты, не будучи обремененным тем, как дизайнер интерфейса подумал, что я должен создать свой класс.

Сказав это, парадигма mixin в значительной степени уникальна для C ++. Без этого я ожидаю, что наследование будет очень привлекательным для прагматичного программиста.

0
8.01.2009 07:12:18

Я считаю, что лучшим механизмом повторного использования кода, который иногда достигается с помощью наследования, являются черты . Посмотрите эту ссылку (pdf), чтобы обсудить это, в том числе различие между чертами и миксинами, и почему предпочтения таковы.

Есть некоторые исследования, которые вводят черты в C # (pdf) .

У Perl есть черты через Moose :: Roles . Черты Scala похожи на миксины , как в Ruby .

1
15.06.2010 20:22:52