Чистые виртуальные функции в С++ 11
В С++ 98 нулевой указатель был представлен литералом 0
(или фактически любым постоянным выражением, значение которого равно нулю). В С++ 11 вместо этого мы предпочитаем nullptr
. Но это не работает для чистых виртуальных функций:
struct X
{
virtual void foo() = nullptr;
};
Почему это не работает? Разве это не будет иметь общего смысла? Это просто недосмотр? Будет ли это исправлено?
Ответы
Ответ 1
Потому что синтаксис говорит 0
, а не выражение или другое нетерминальное соответствие nullptr
.
За все время работало только 0
. Даже 0L
будет плохо сформирован, потому что он не соответствует синтаксису.
Edit
Clang позволяет = 0x0
, = 0b0
и = 00
(31.12.2013). Это неверно и должно быть исправлено в компиляторе, конечно.
Ответ 2
Обозначение = 0
для функций virtual
не буквально "присваивало null", а скорее специальную нотацию, которая на самом деле обманчива: можно также реализовать чистую виртуальную функцию.
С различными ключевыми словами контекста было бы целесообразнее разрешить abstract
, а не = nullptr
, а abstract
- ключевое слово контекста.
Ответ 3
Именно так определяется грамматика, если мы посмотрим на черновик проекта С++ 9.2
Члены класса, соответствующая грамматика выглядит следующим образом:
[...]
member-declarator:
declarator virt-specifier-seqopt pure-specifieropt
[...]
pure-specifier:
= 0
^^^
В грамматике конкретно указывается, что спецификатор pure-specifier = 0
, а не целостный литерал или выражение, которое, похоже, не оставляет комнаты для маневра. Если я попытаюсь сделать такие вещи, как:
virtual void foo() = 0L;
или
virtual void foo() = NULL ;
gcc
говорит мне:
ошибка: недопустимый чистый спецификатор (разрешено только '= 0') до ';' Маркер
и clang
говорит:
Ошибка: функция initializer on не похожа на чисто спецификатор
Хотя в обоих случаях работает следующее:
#define bar 0
//...
virtual void foo() = bar;
Также кажется, что clang
допускает восьмеричный литерал, шестнадцатеричный литерал и двоичный литерал нуль, который является неправильным поведением.
Обновить
По-видимому Visual Studio
принимает NULL
и любой нулевой целочисленный литерал, включающий 0L
, 0x0
, 00
и т.д.... Хотя он не принимает nullptr
.
Ответ 4
= 0
имеет там фиксированное значение. На самом деле это не целая ноль. Поэтому вы не можете просто заменить его таким образом.
Ответ 5
Вся точка nullptr
(или большая часть точки в любом случае) заключается в том, что она может быть назначена (или используется для инициализации) указателями.
В этом случае вы не инициализируете или не назначаете указатель, поэтому даже не имеет смысла, что вы сможете использовать его в этой ситуации.
Ответ 6
Синтаксис = 0
не использовался для инициализации указателя, он просто указывал синтаксически, что предоставленный virtual
был чистым.
Следовательно, синтаксис = 0
для объявления pure virtual
не изменяется.
Ответ 7
Это не значит, что это указатель или он должен быть равен nullptr
.
= 0
является достаточным и означает, что виртуальная функция должна быть чистой.
Ответ 8
В грамматике С++ 11 допускается только 0
(и это не означает указатель). Поскольку nullptr
не 0
, он терпит неудачу. NULL
работает только тогда, когда NULL
определяется как 0
(иногда это случай, но не всегда). Просто используйте 0
здесь или используйте следующий define (если вы действительно хотите использовать null, если это не указатель).
#define VIRTUAL_NULL 0
struct X
{
virtual void foo() = VIRTUAL_NULL;
};