Во-первых, необходимо отметить, что mixins только существуют на языках множественного наследования. Вы не можете сделать смешивания в Java или C#.
В основном, смешивание является автономным базовым типом, который обеспечивает ограниченную функциональность и полиморфный резонанс для дочернего класса. Если Вы думаете в C#, думаете об интерфейсе, который Вы не должны на самом деле реализовывать, потому что он уже реализован; Вы просто наследовались ему и преимущество от его функциональности.
Mixins являются обычно узкими в объеме и не предназначенные, чтобы быть расширенными.
[редактирование - относительно почему:]
я предполагаю, что должен обратиться, почему, так как Вы спросили. Большое преимущество - то, что Вы не должны делать этого сами много раз. В C# самое большое место, где смешивание могло извлечь выгоду, могло бы быть от шаблон Распоряжения . Каждый раз, когда Вы реализуете IDisposable, Вы почти всегда хотите следовать за тем же шаблоном, но Вы заканчиваете тем, что писали и переписали тот же абсолютный код с незначительными изменениями. Если бы было растяжимое смешивание Распоряжения, то Вы могли бы сохранить себя большой дополнительный ввод.
[редактируют 2 - для ответа на другие вопросы]
, Что разделяет смешивание от множественного наследования? Это - просто вопрос семантики?
Да. Различием между смешиванием и стандартным множественным наследованием является просто вопрос семантики; класс, который имеет множественное наследование, мог бы использовать смешивание как часть того множественного наследования.
точка смешивания должна создать тип, который может быть "смешан в" к любому другому типу через наследование, не влияя на наследовавшийся тип, все еще предлагая некоторую выгодную функциональность для того типа.
Снова, думайте об интерфейсе, который уже реализован.
я лично не использую mixins, так как я разрабатываю, прежде всего, на языке, который не поддерживает их, таким образом, мне действительно тяжело придумывать достойный пример, который просто предоставит это "ahah!" момент для Вас. Но я попробую еще раз. Я собираюсь использовать пример, который это изобрело - большинство языков уже обеспечивает функцию так или иначе - но это, надо надеяться, объяснит, как mixins, как предполагается, создаются и используются. Здесь идет:
предположим у Вас есть тип, который Вы хотите смочь сериализировать к и от XML. Вы хотите, чтобы тип предоставил метод "ToXML", который возвращает строку, содержащую фрагмент XML со значениями данных типа и "FromXML", который позволяет типу восстанавливать свои значения данных от фрагмента XML в строке. Снова, это - изобретенный пример, поэтому возможно, Вы используете поток файла или Класс для записи XML от библиотеки времени выполнения Вашего языка... без разницы. Дело в том, что Вы хотите сериализировать свой объект к XML и вернуть новый объект от XML.
другой важный момент в этом примере - то, что Вы хотите сделать это универсальным способом. Вы не хотите должными быть реализовывать "ToXML" и метод "FromXML" для каждого типа, который Вы хотите сериализировать, Вы хотите некоторые универсальные средства обеспечения, что Ваш тип сделает это, и это просто работает. Вы хотите повторное использование кода.
, Если Ваш язык поддерживал его, Вы могли бы создать XmlSerializable mixin, чтобы сделать Вашу работу для Вас. Этот тип реализовал бы ToXML и методы FromXML. Это было бы, с помощью некоторого механизма, это не важно для примера, быть способным к сбору всех необходимых данных из любого типа, что это смешано в с создать фрагмент XML, возвращенный ToXML, и это было бы одинаково способно к восстановлению тех данных, когда FromXML называют.
И..именно. Для использования его у Вас был бы любой тип, который должен быть сериализирован к XML, наследовались XmlSerializable. Каждый раз, когда необходимо было сериализировать или десериализовать тот тип, Вы просто назовете ToXML или FromXML. На самом деле, так как XmlSerializable является абсолютным типом и полиморфный, Вы могли очевидно создать сериализатор документа, который ничего не знает о Вашем исходном типе, принимая только, скажем, массив типов XmlSerializable.
Теперь предполагают использовать этот сценарий для других вещей, как создание смешивания, которое гарантирует, что каждый класс, который смешивает его в журналах каждый вызов метода или смешивание, которое предоставляет transactionality типу, который смешивает его в. Список может продолжиться и на.
, Если Вы просто думаете о смешивании как о небольшом базовом типе, разработанном для добавления небольшого количества функциональности к типу, иначе не влияя на тот тип, затем Вы являетесь золотыми.
, Надо надеяться. :)
Вашему базовому классу нужен виртуальный деструктор. В противном случае деструктор производного класса не будет вызываться, если используется только указатель типа A *.
Добавьте
virtual ~A() {};
к классу A.
Класс A должен иметь виртуальный деструктор. Без этого деструкторы производного класса не будут вызываться.
попробуйте следующее:
class A
{
public:
virtual ~A() {}
virtual f();
};
class B : public A
{
public:
B()
{
p = new char [100];
}
virtual ~B() // virtual keywork optional but occasionally helpful for self documentation.
{
delete [] p;
}
f();
private:
char *p;
};
Если ваша переменная относится к типу A, у нее нет виртуального деструктора, поэтому она не будет смотреть на фактический тип среды выполнения объекта, чтобы определить, что ему нужно вызвать деструктор
Добавьте пустой деструктор в A
virtual ~ A () {}
, и это должно исправить это.
В общем, вам необходимо сделайте это для любого класса, который может быть использован в качестве базового.