a
как a a1()
, это не вызывает ошибку, но не вызывает конструктор. Почему это происходит?Мой код:
#include<iostream>
using namespace std;
class a
{
public:
a()
{
cout << "in a\n";
}
};
int main()
{
a a1();
a a;
}
Когда ты пишешь a a1();
фактически он анализируется как объявление функции, а не как вызов конструктора по умолчанию.
a a1;
правильно вызовет конструктор по умолчанию
Когда ты пишешь a a;
это работает, потому что имя переменной имеет преимущество перед именем класса в том, что называется скрытием имени, но даже если это работает, это только приведет к путанице, и я бы избегал этого.
И для всех тех, кто любит стандарты цитаты здесь вы идете
Имя класса (9.1) или имя перечисления (7.2) может быть скрыто по имени переменной, члена данных, функции или перечислителя, объявленных в той же области. Если имя класса или перечисления и переменная, член данных, функция или перечислитель объявлены в одной и той же области (в любом порядке) с одинаковым именем, имя класса или перечисления будет скрыто везде, где переменная, член данных, функция или Имя перечислителя видно.
a a1();
это объявление функции.
Это важная причина для создания единой инициализации в C ++ 11. Чтобы инициализировать объект с помощью конструктора в C ++ 11, используйте a a1{};
На самом деле, если вы посмотрите на C ++ черновик стандартного раздела 3.3.10
Имя скрывается параграф 2 говорит (акцент мой):
Имя класса (9.1) или имя перечисления (7.2) может быть скрыто по имени переменной, элемент данных, функция или перечислитель, объявленные в той же области видимости. Если имя класса или перечисления и переменная, член данных, функция или перечислитель объявлены в одной и той же области (в любом порядке) с одинаковым именем, имя класса или перечисления будет скрыто везде, где переменная, член данных, функция или имя перечислителя
видимый.
Я не думаю, что это хорошая практика, и это приведет к трудностям в поддержании кода. Эта строка кода фактически объявляет функцию:
a a1();
Вы можете альтернативно использовать этот предварительныйC ++ 11:
a a1 ;
или же равномерная инициализация введено в C ++ 11 :
a a1{} ;
Возвращаясь к сокрытие имени, Я был приятно удивлен, увидев, что clang
предупредит вас об этом с помощью этого кода независимо от установленных уровней предупреждения:
int main()
{
a a;
a a2 ;
}
Я получаю это сообщение:
main.cpp:12:10: note: class 'a' is hidden by a non-type declaration of 'a' here
a a;
^
хотя я не вижу, чтобы получить подобное предупреждение от gcc
,
Обновить
Думая об этом комментарии, которые я сделал ранее бородавки равномерной инициализации, Я понял, что ты подозревал, что a1
был как-то не тот тип, который вы могли бы использовать TypeId отладить то, что происходило. Например этот код:
std::cout << typeid(a).name() << std::endl ;
std::cout << typeid(a1).name() << std::endl ;
результаты в этом выводе на Coliru живой пример:
1a
F1avE
и проходя через C ++ ФИЛТР Вы получаете этот вывод:
a () // A function that returns type a
a // type a
a a1();
является типом возврата объявления функции как a
который не имеет ничего общего с вызывающим конструктором
a a ;
простое утверждение отлично работает вызовет конструктор
Это то, что я получил из вашего кода, когда пытался скомпилировать его с clang
Я думаю, это говорит обо всем.
test.cpp:15:9: warning: empty parentheses interpreted as a function declaration
[-Wvexing-parse]
a a1();
^~
test.cpp:15:9: note: remove parentheses to declare a variable
a a1();
^~
1 warning generated.