Как это можно использовать в С++?
- К моему удивлению, я обнаружил, что имя объекта С++ может быть таким же, как имя класса. Может кто-нибудь объяснить мне причину, почему?
- Когда я объявляю объект класса
a
как a a1()
, он не вызывает ошибку, но не вызывает конструктор. Почему это происходит?
Мой код:
#include<iostream>
using namespace std;
class a
{
public:
a()
{
cout << "in a\n";
}
};
int main()
{
a a1();
a a;
}
Ответы
Ответ 1
Когда вы пишете a a1();
, он фактически анализируется как объявление функции, а не вызов конструктора по умолчанию.
a a1;
правильно вызовет конструктор по умолчанию
Когда вы пишете a a;
, это работает, потому что имя переменной берет предпочтение над именем класса в том, что называется скрытием имени, но даже при том, что оно работает, это приведет только к путанице, и я бы не стал делать это.
И для всех тех людей, которые, как стандарты, цитируют здесь, вы идете
Имя класса (9.1) или имя перечисления (7.2) можно скрыть именем переменной, членом данных, функцией или перечислителем, объявленным в той же области. Если имя класса или перечисления и переменная, член данных, функция или перечислитель объявляются в той же области (в любом порядке) с тем же именем, имя класса или перечисления скрыто везде, где переменная, член данных, функция или имя счетчика видно.
Ответ 2
a a1();
- это объявление функции.
Это важная причина для создания равномерной инициализации в С++ 11. Чтобы инициализировать объект с помощью конструктора в С++ 11, используйте a a1{};
Ответ 3
Можно скрыть имя класса с переменной на самом деле, если вы посмотрите на стандартный проект стандарта С++ 3.3.10
Сокрытие названия в параграфе 2 говорит (внимание мое):
Имя класса (9.1) или имя перечисления (7.2) можно скрыть именем переменной, членом данных, функцией или перечислителем, объявленным в той же области. Если имя класса или перечисления и переменная, член данных, функция или перечислитель объявляются в той же области (в любом порядке) с тем же именем, имя класса или перечисления скрыто везде, где переменная, член данных, функция или имя счетчика видны.
Я не думаю, что это хорошая практика, и это приведет к сложному поддержанию кода. Эта строка кода фактически объявляет функцию:
a a1();
вы также можете использовать этот pre-С++ 11:
a a1 ;
или равномерная инициализация, введенная в С++ 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 ;
выводит этот результат на Пример Live в Coliru:
1a
F1avE
и передавая его через c++filt, вы получаете этот результат:
a () // A function that returns type a
a // type a
Ответ 4
a a1();
- это возвращаемый тип объявления функции как a
, который не имеет ничего общего с вызывающим конструктором
a a ;
- простой оператор, который отлично работает, вызовет конструктор
Ответ 5
Это то, что я получил от вашего кода при попытке скомпилировать его с помощью 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.