Моя обычная коллекция статей управления памятью какао:
Чтобы подробно остановиться на ответе bradtgmurray, можно хотеть сделать одно исключение к чистому виртуальному списку методов интерфейса путем добавления виртуального деструктора. Это позволяет Вам передавать владение указателя другой стороне, не представляя конкретный производный класс. Деструктор ничего не должен делать, потому что интерфейс не имеет никаких конкретных участников. Это могло бы казаться противоречащим, чтобы определить функцию и как виртуальную и встроить, но доверять мне - это не.
class IDemo
{
public:
virtual ~IDemo() {}
virtual void OverrideMe() = 0;
};
class Parent
{
public:
virtual ~Parent();
};
class Child : public Parent, public IDemo
{
public:
virtual void OverrideMe()
{
//do stuff
}
};
Вы не должны включать тело для виртуального деструктора - оказывается, что некоторые компиляторы испытывают затруднения при оптимизации пустого деструктора, и Вы - более обеспеченное использование значения по умолчанию.
Можно также считать классы контракта реализованными с NVI (Не Виртуальный Интерфейсный Шаблон). Например:
struct Contract1 : boost::noncopyable
{
virtual ~Contract1();
void f(Parameters p) {
assert(checkFPreconditions(p)&&"Contract1::f, pre-condition failure");
// + class invariants.
do_f(p);
// Check post-conditions + class invariants.
}
private:
virtual void do_f(Parameters p) = 0;
};
...
class Concrete : public Contract1, public Contract2
{
private:
virtual void do_f(Parameters p); // From contract 1.
virtual void do_g(Parameters p); // From contract 2.
};
Немного дополнения к тому, что описано там:
Первый, удостоверьтесь, что Ваш деструктор также чист виртуальный
112-секундный, можно хотеть наследоваться фактически (а не обычно), когда Вы действительно реализуете, только для хороших мер.
Мой ответ является в основном тем же как другими, но я думаю, что существует две других важных вещи сделать:
Объявляют виртуальный деструктор в Вашем интерфейсе или делают защищенный невиртуальный для предотвращения неопределенных поведений, если кто-то пытается удалить объект Использования типа IDemo
.
виртуальное наследование для предотвращения проблем со множественным наследованием. (Существует чаще множественное наследование, когда мы используем интерфейсы.)
И как другие ответы:
Использование интерфейс путем создания другого класса, который переопределяет те виртуальные методы.
class IDemo
{
public:
virtual void OverrideMe() = 0;
virtual ~IDemo() {}
}
Или
class IDemo
{
public:
virtual void OverrideMe() = 0;
protected:
~IDemo() {}
}
И
class Child : virtual public IDemo
{
public:
virtual void OverrideMe()
{
//do stuff
}
}
Нет никакого понятия "интерфейса" по сути в C++. AFAIK, интерфейсы были сначала представлены в Java для работы вокруг отсутствия множественного наследования. Это понятие оказалось довольно полезным, и тот же эффект может быть достигнут в C++ при помощи абстрактного базового класса.
абстрактный базовый класс является классом, в котором по крайней мере одна функция членства (метод в малопонятном жаргоне Java) является чистой виртуальной функцией, объявил использование следующего синтаксиса:
class A
{
virtual void foo() = 0;
};
абстрактный базовый класс нельзя инстанцировать, т.е. Вы не можете объявить объект класса A. Можно только получить классы из A, но любой производный класс, который не обеспечивает реализацию foo()
, также будет абстрактен. Чтобы прекратить быть абстрактным, производный класс должен обеспечить реализации для всех чистых виртуальных функций, которые он наследовал.
Примечание, что абстрактный базовый класс может быть больше, чем интерфейс, потому что это может содержать элементы данных и функции членства, которые не являются чисты виртуальный. Эквивалент интерфейса был бы абстрактным базовым классом без любых данных только с чистыми виртуальными функциями.
И, как Mark Ransom указал, абстрактный базовый класс должен обеспечить виртуальный деструктор, точно так же, как любой базовый класс, в этом отношении.
Целая причина у Вас есть специальная Интерфейсная категория типа в дополнение к абстрактным базовым классам в C# / Java, состоит в том, потому что C#/Java не поддерживают множественное наследование.
C++ поддерживает множественное наследование, и таким образом, специальный тип не необходим. Абстрактный базовый класс без некраткого обзора (чистый виртуальный) методы функционально эквивалентен интерфейсу C#/Java.
Сделайте класс с чистыми виртуальными методами. Используйте интерфейс путем создания другого класса, который переопределяет те виртуальные методы.
А чистый виртуальный метод является методом класса, который определяется как виртуальный и присвоенный 0.
class IDemo
{
public:
virtual ~IDemo() {}
virtual void OverrideMe() = 0;
};
class Child : public IDemo
{
public:
virtual void OverrideMe()
{
//do stuff
}
};
Все хорошие ответы выше. Одна дополнительная вещь, которую необходимо иметь в виду - у Вас может также быть чистый виртуальный деструктор. Единственная разница - то, что все еще необходимо реализовать его.
Запутанный?
--- header file ----
class foo {
public:
foo() {;}
virtual ~foo() = 0;
virtual bool overrideMe() {return false;}
};
---- source ----
foo::~foo()
{
}
главная причина Вы хотели бы сделать, это - то, если Вы хотите обеспечить методы интерфейса, как я имею, но делаю переопределение их дополнительным.
Для создания класса интерфейсный класс требует чистого виртуального метода, но все виртуальные методы имеют реализации по умолчанию, таким образом, единственный метод, оставленный сделать чистым виртуальный, является деструктором.
Перереализация деструктора в производном классе не является никаким грандиозным предприятием вообще - я всегда повторно реализую деструктор, виртуальный или нет, в моих производных классах.
Если вы используете компилятор Microsoft C ++, тогда вы можете сделать следующее:
struct __declspec(novtable) IFoo
{
virtual void Bar() = 0;
};
class Child : public IFoo
{
public:
virtual void Bar() override { /* Do Something */ }
}
Мне нравится этот подход, потому что он приводит к намного меньшему размеру кода интерфейса, а размер сгенерированного кода может быть значительно меньше. Использование novtable удаляет все ссылки на указатель vtable в этом классе, поэтому вы никогда не сможете создать его экземпляр напрямую. См. Документацию здесь - novtable .