Наиболее раздражающая ошибка разбора: конструктор без аргументов
Я компилировал программу на C++ в Cygwin с использованием g++ и у меня был класс, у которого конструктор не имел аргументов. У меня были следующие строки кода:
MyClass myObj();
myObj.function1();
При попытке скомпилировать код я получил сообщение об ошибке:
error: request for member 'function1' in 'myObj', which is of non-class type 'MyClass ()()'
После небольшого исследования я узнал, что решение проблемы состоит в том, чтобы изменить первую строку на:
MyClass myObj;
Я клянусь, что раньше использовал объявления конструкторов без аргументов с круглыми скобками в C++. Это, вероятно, ограничение компилятора, который я использую, или стандарт языка действительно гласит, что нельзя использовать круглые скобки для конструктора без аргументов?
5 ответ(ов)
Хотя выражение MyClass myObj();
может быть интерпретировано как определение объекта с пустым инициализатором или как объявление функции, стандарт языка предписывает разрешать эту неоднозначность в пользу объявления функции. Пустой инициализации в виде круглых скобок разрешена в других контекстах, например, в выражении new
или при создании временного объекта, инициализированного значением.
В стандарте C++ (§8.5.8) указано следующее:
Объекты, инициализируемые пустым набором круглых скобок, т.е. (), должны быть инициализированы по значению.
[Примечание: поскольку () не допускается синтаксисом для инициализаторов,
X a ();
это не объявление объекта класса X, а объявление функции, которая не принимает аргументов и возвращает объект типа X. Форма () разрешена в некоторых других контекстах инициализации (5.3.4, 5.2.3, 12.6.2). —конец примечания ]
Таким образом, имея X a();
, вы фактически создаете объявление функции, а не объекта. Если же вы хотите инициализировать объект, вам нужно использовать другой синтаксис, например, X a;
или X a{};
, чтобы создать объект класса X.
Конструкция MyClass myObj();
интерпретируется компилятором как объявление функции, которая называется myObj
, не принимает аргументов и возвращает объект типа MyClass
. Такое поведение является стандартным в C++. Возможно, вы никогда не видели компиляторов, принимающих такую запись, скорее всего, это связано с тем, что она часто вызывает недоразумения.
С другой стороны, конструкция MyClass* myPtr = new MyClass();
является корректной. Здесь мы создаем указатель myPtr
, который указывает на новый объект типа MyClass
, и это может быть причиной вашего недоразумения. Чтобы создать объект MyClass
на стеке, вы можете использовать следующую запись: MyClass myObj;
.
Ваш код заставляет компилятор думать, что вы объявляете функцию с именем myObj
, которая не принимает аргументов и возвращает MyClass
. Это неопределенность действительно может быть раздражающей.
Стандарт не требует использования круглых скобок.
int* x = new int;
— это корректный синтаксис.
В вашем случае myclass myobj();
является прототипом функции. В то время как myclass myobj;
— это объявление переменной.
Новые возможности C++17: что стоит знать?
Имеют ли круглые скобки после имени типа значение при использовании new?
Каковы правила вызова конструктора базового класса?
Сколько конструкторов у класса?
Что означает && в конце сигнатуры функции (после закрывающей скобки)?