Подтвердить что ты не робот

Как это можно использовать в С++?

  • К моему удивлению, я обнаружил, что имя объекта С++ может быть таким же, как имя класса. Может кто-нибудь объяснить мне причину, почему?
  • Когда я объявляю объект класса a как a a1(), он не вызывает ошибку, но не вызывает конструктор. Почему это происходит?

Мой код:

#include<iostream>
using namespace std;

class a 
{
    public:
    a() 
    {
        cout << "in a\n";
    }
};

int main()
{
    a a1();
    a a;
}
4b9b3361

Ответ 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.