How is this possible to use in c++?
Asked Answered
F

5

17
  1. To my surprise, I found that the name of a c++ object can be the same as class name. Can someone explain to me the reason why?
  2. When I declare an object of class a as a a1(), it does not raise an error, but doesn't call the constructor. Why is this happening?

My code:

#include<iostream>
using namespace std;

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

int main()
{
    a a1();
    a a;
}
Frizzle answered 8/10, 2013 at 14:33 Comment(12)
a1 isn't an object, but a function.Freeway
This is not the "most vexing parse". It is simply a function declaration. The most vexing parse involves a function call with a temporary argument.Beaufort
@PeteBecker Technically correct, but we don't have a separate somewhat-vexing-parse tag ;)Soffit
@FredOverflow - while the question should be closed as a duplicate, it shouldn't be linked to an answer that has nothing to do with the problem, even if there isn't a suitable tag.Beaufort
@PeteBecker I doubt we will find a duplicate that covers both his questions.Soffit
@TemplateRex can you explain why you added back the most-vexing-parse tag when it was determined to not be relevant?Shearwater
@ShafikYaghmour sorry, I didn't read the comments in detail, and as Fred Overflow mentioned, there is not somewhat vexing parse tagGoldagoldarina
@Goldagoldarina I'd say it's at least a highly-vexing-parse anywayIatrogenic
Don't forget that you can use struct and class just as you could in C to make it less confusing. class a a; reads better than a a;. I ran into this in real life with a class named url and a variable named url. So it was class url url;Passional
(Sorta) related question: #4425490History
@PeteBecker you know I was reading Effective STL again and it seems that it actually is covered under the most vexing parse, he refers to this case as another manifestation of this rule.Shearwater
@ShafikYaghmour - X f() is a function declaration, just as int f() is. It may well be similar in appearance, but it's not the same thing at all. "another manifestation of the rule" is not the same as "equally obscure and confusing and deserving of a derogatory name".Beaufort
I
21

When you write a a1(); it is actually being parsed as a function declaration not a call to the default constructor.

a a1;

will call the default constructor correctly

When you write a a; it works because the variable name takes preference over the class name in what is called name hiding, but even though it works it will only lead to confusion and I would avoid doing it.

And for all those people who like standards quotes here you go

A class name (9.1) or enumeration name (7.2) can be hidden by the name of a variable, data member, function, or enumerator declared in the same scope. If a class or enumeration name and a variable, data member, function, or enumerator are declared in the same scope (in any order) with the same name, the class or enumeration name is hidden wherever the variable, data member, function, or enumerator name is visible.

Iatrogenic answered 8/10, 2013 at 14:35 Comment(5)
"yes it works..." is no explanation. I would have expected something like: The local definition of variable a hides the type name to avoid interference with externally (included) names.Petrinapetrine
@Nobody I'm not a big fan of just quoting the standard for every simple question, also that wasn't the main questionIatrogenic
I did not say to quote the standard (although it is always nice to have a definitive authoritative answer). Some reasoning like in my commentary would have been enough.Petrinapetrine
@Nobody picky people keep the quality of this site high :)Iatrogenic
@Nobody Answers should be not just for the OP but future readers as well so asking for more complete answers is never a bad thing. Not everyone feels as comfortable quoting the standard and that is ok.Shearwater
K
8

a a1(); is a function declaration.

That's an important reason for the creation of uniform initialization in C++11. To initialize the object using the constructor in C++11, use a a1{};

Kinzer answered 8/10, 2013 at 14:38 Comment(1)
@PeteBecker also uniform initialization also has it's own warts as we can see here.Shearwater
S
4

It is valid to hide the name of a class with a variable in fact if you look at the C++draft standard section 3.3.10 Name hiding paragraph 2 says(emphasis mine):

A class name (9.1) or enumeration name (7.2) can be hidden by the name of a variable, data member, function, or enumerator declared in the same scope. If a class or enumeration name and a variable, data member, function, or enumerator are declared in the same scope (in any order) with the same name, the class or enumeration name is hidden wherever the variable, data member, function, or enumerator name is visible.

I don't think it is good practice and it would lead to hard to maintain code. This line of code is actually declaring a function:

a a1();

you can alternatively use this pre-C++11:

a a1 ;

or uniform initialization introduced in C++11 :

a a1{} ;

Circling back to name hiding, I was pleasantly surprised to see that clang will warn you about this with this code regardless of the warning levels set:

int main()
{
   a a;
   a a2 ;
}

I receive this message:

main.cpp:12:10: note: class 'a' is hidden by a non-type declaration of 'a' here
   a a;
     ^

although I can't see to obtain a similar warning from gcc.

Update

Thinking about this comments I made earlier on warts of uniform initialization, I realized that had you suspected that a1 was somehow not the correct type you could have have used typeid to debug what was going on. For example this code:

std::cout << typeid(a).name() << std::endl ;
std::cout << typeid(a1).name() << std::endl ;

results in this output on Coliru live example:

1a
F1avE

and passing it through c++filt you receive this output:

a ()     // A function that returns type a
a        // type a
Shearwater answered 8/10, 2013 at 14:41 Comment(0)
P
0

a a1(); is a function declaration return type as a which has nothing to do with the calling constructor

a a ; is simple statement works fine will call the constructor

Peanut answered 8/10, 2013 at 14:35 Comment(0)
M
0

This is what I got from your code when tried to compile it with clang, I think it says everything.

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.
Mcbryde answered 19/10, 2013 at 13:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.