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;
}
TemplateRex
  • 69,038
  • 19
  • 164
  • 304
nihar
  • 153
  • 9
  • 15
    `a1` isn't an object, but a function. – Luchian Grigore Oct 08 '13 at 14:35
  • 4
    This is **not** the "most vexing parse". It is simply a function declaration. The [most vexing parse](http://en.wikipedia.org/wiki/Most_vexing_parse) involves a function call with a temporary argument. – Pete Becker Oct 08 '13 at 15:31
  • 1
    @PeteBecker Technically correct, but we don't have a separate [tag:somewhat-vexing-parse] tag ;) – fredoverflow Oct 08 '13 at 15:59
  • 1
    @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. – Pete Becker Oct 08 '13 at 16:03
  • 1
    @PeteBecker I doubt we will find a duplicate that covers both his questions. – fredoverflow Oct 08 '13 at 16:13
  • @TemplateRex can you explain why you added back the `most-vexing-parse` tag when it was determined to not be relevant? – Shafik Yaghmour Oct 08 '13 at 19:20
  • @ShafikYaghmour sorry, I didn't read the comments in detail, and as Fred Overflow mentioned, there is not somewhat vexing parse tag – TemplateRex Oct 08 '13 at 19:25
  • @TemplateRex I'd say it's at least a highly-vexing-parse anyway – aaronman Oct 08 '13 at 19:33
  • 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;` – Zan Lynx Oct 08 '13 at 20:07
  • (Sorta) related question: http://stackoverflow.com/questions/4424990/how-do-i-make-define-and-declare-a-variable-using-the-default-constructor-in-c/4425002#4425002 – LeopardSkinPillBoxHat Oct 08 '13 at 21:24
  • @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*. – Shafik Yaghmour Nov 27 '13 at 05:06
  • @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". – Pete Becker Nov 27 '13 at 15:48

5 Answers5

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.

aaronman
  • 18,343
  • 7
  • 63
  • 78
  • 2
    "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. – Nobody moving away from SE Oct 08 '13 at 14:41
  • @Nobody I'm not a big fan of just quoting the standard for every simple question, also that wasn't the main question – aaronman Oct 08 '13 at 14:43
  • 2
    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. – Nobody moving away from SE Oct 08 '13 at 14:44
  • @Nobody picky people keep the quality of this site high :) – aaronman Oct 08 '13 at 14:51
  • @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. – Shafik Yaghmour Oct 08 '13 at 14:57
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{};

segfault
  • 5,759
  • 9
  • 45
  • 66
  • @PeteBecker also uniform initialization also has it's own warts as we can see [here](http://stackoverflow.com/questions/16571725/why-would-they-special-case-certain-initializer-lists-instead-of-treating-them-a). – Shafik Yaghmour Oct 08 '13 at 17:08
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
Community
  • 1
  • 1
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
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

P0W
  • 46,614
  • 9
  • 72
  • 119
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.
Zaffy
  • 16,801
  • 8
  • 50
  • 77