2015-08-03 6 views
1

У меня есть абстрактный базовый класс, который служит для создания массива указателей на базовый класс. (Полезно для «многих вещей» ...)C++: Как создать абстрактный базовый класс, если класс не имеет функций-членов?

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

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

Возможно ли создать бесклассовый абстрактный базовый класс? Если нет, есть ли еще одна резолюция о предотвращении создания экземпляра моей «абстрактной базы»? Будет ли делать конструктор protected?

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

+0

содержит ли переменные-члены? –

+6

Каким будет использование такой вещи? Это базовый класс, но в нем ничего нет? – Barry

+4

@Barry Разве вы не читали вопрос? '(Полезно для« многих вещей »...)';) – fredoverflow

ответ

11

Обеспечить чистый виртуальный деструктор:

struct Base { 
virtual ~Base() = 0; 
}; 

inline Base::~Base() {} 

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


Абстрактный класс является классом с некоторой чистой виртуальной функции:

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

[N4431 §10.4/2]

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

Base * instance = // ... whatever ... 
delete instance; 

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

Так как это виртуально в любом случае, и вам не нужна какая-то чистая виртуальная функция-член, лучше всего сделать деструктор чистым виртуальным.

Чтобы сделать виртуальную функцию чистой, вы добавите чисто-спецификатор в своей декларации:

struct Foo { 
virtual void bar(void) /* the */ = 0; // pure-specifier 
}; 

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

[...] Чистая виртуальная функция должна быть определена только при вызове с или, как если бы с (12.4), синтаксисом квалифицированного идентификатора (5.1). [...]

[N4431 §10.4/2]

Это потому, что, когда разрушающее производный класс, после того, как производные классы деструктор был вызван, также будут называть деструкторы классов оснований:

struct Derived : public Base { 
~Derived() { 
    // contents 
    // Base::~Base() will be called 
} 
}; 

После выполнения тела деструктора [...] деструктор для класса X вызовов [...] деструкторы для классов прямых базовых иксов и, если X является типом наиболее производным класса (12,6 .2), его деструктор вызывает деструкторы для виртуса X базовых классов. Все деструкторы вызываются, как если бы они были ссылки с составным именем [...]

[N4431 §12.4/8]

Так определение чистого виртуального деструктора, если Base класс необходим. Однако ...

[...] Объявление функции не может обеспечить как чисто-спецификатор и определение [...]

[N4431 §10.4/2]

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

Инлайн функция должна быть определена в каждом единице трансляции, в которой он ODR используются и должны иметь точно такое же определение в каждом конкретном случае [ ...]

[N4431 §7.1.2/4]

... как inline функции в заголовке.


Стандарт даже явный о требовании определения в этом случае:

Деструктор может быть объявлен виртуальным (10.3) или чисто виртуальным (10.4); если в программе создаются какие-либо объекты этого класса или любого производного класса, деструктор должен быть определен. [...]

[N4431 §12.4/9]

+0

Как это чисто виртуально, если есть реализация? – user3728501

+1

, потому что в декларации есть '= 0'. –

+0

@ user3728501 это чистый виртуальный, потому что производные классы вынуждены переопределять его. – Quentin

1

Можно ли создать memberless абстрактный базовый класс?

Самый простой способ - сделать деструктор чистым виртуальным.

class AbstractBase 
{ 
    public: 
     virtual ~AbstractBase() = 0; 
}; 
+0

А это может быть хорошим решением – user3728501

1

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

Если, однако, вы вообще не используете полиморфизм, вам следует избегать добавления виртуального деструктора и вместо этого просто защищать конструктор. Помните, что базовый класс необязательно должен устанавливать иерархию полиморфных классов (см. Примеры в библиотеке C++, например std::input_iterator_tag).