views:

865

answers:

5

Earlier I asked why this is considered bad:

class Example
{
 public: 
  Example(void);
  ~Example(void);
  void f() {}
}

int main(void)
{
 Example ex(); // <<<<<< what is it called to call it like this?

 return(0);
}

Now, I understand that it's creating a function prototype instead that returns a type Example. I still don't get why it would work in g++ and MS VC++ though.

My next question is using the above, would this call be valid?

int main(void)
{
 Example *e = new Example();

 return(0);
}

? What is the difference between that and simply calling Example e()??? Like I know it's a function prototype, but it appears maybe some compilers forgive that and allow it to call the default constructor? I tried this too:

class Example
{
 private:
  Example();

 public:
  ~Example();
};

int main(void)
{
 Example e1(); // this works
 Example *e1 = new Example(); // this doesn't

 return(0);
}

So I'm a bit confused :( Sorry if this been asked a million times.

+1  A: 

this question will be helpful to understand this behavior

yesraaj
Hey, thanks. So I guess it's the "vexing parse" problem. Yeah, amazing, I always used Example e(); and never ran into the problem with MS VC++ (VS 2005) and gnu g++ (don't remember the version). So this is all new to me.... guess you learn something new everyday.
Daniel
:-) .
yesraaj
+4  A: 

It's easy, Daniel:

Example *e = new Example();

That doesn't look like a function called "Example", does it? A function has a return value, a name and parameters. How would the above fit that?

Example e1(); // this works

Yeah, because you don't create any instance of Example anywhere. You just tell the code that there is a function defined in the surrounding namespace somewhere, and you possibly want to call that function. Yes, it's true that in order to return a object of Example, an instance would be made. But that doesn't mean an instance is made at that point. Rather, an instance is made in the function, when you call it.

Johannes Schaub - litb
"Example e1();" has no returnvalue either, but still it looks like a function. I'ld rather say that the =-sign and the new keyword make it unambiguously clear it's an allocation + constructor call, whose result is stored in a freshly declared pointer variable
xtofl
xtoly. Example e1(); has a return type, it's the "Example" in there :)
Johannes Schaub - litb
+1  A: 

Hmm... OK this:

Example e1();

Doesn't work. You may think it does, or some compiler is accepting it, but it does not create an instance of Example called e1, it just declares a function prototype. Remove the brackets and it does what you want.

This:

Example* e1 = new Example();

Won't work because the constructor is private. If you make the constructor public it will create the object on the heap, and e1 will be a pointer to that object. You will need to delete the object when you are done with it.

Kazade
+1  A: 

For the first question of would the "new Example()" be valid. Yes, this is perfectly legal C++ code. Although to be completely correct you will need to delete the object before returning from main(), otherwise it will lead to a memory leak.

Example:

int main(void)
{
 Example *e = new Example();
 delete e;
 return(0);
}

For the last question. The line "Example e1();" is valid because it is declaring a function prototype. This doesn't actually result in machine code being executed (well maybe stack space). It's simply saying, there is a function prototype with no arguments, returning a type of Example.

The second line though will definately fail. At this point you are attempting to actually execute the constructor for Example. This is not legal as the accessibility of the function is private, hence the compiler error.

JaredPar
A: 

I think you should differentiate between 'this parses', 'this compiles', 'this links' and 'this works', and try to think like a C++ parser/compiler/linker yourself to see that the first example

Example e1(); // function prototype

looks like a function declaration. The parser will understand it thusly, so you cannot call e.g. a member function on e1. The compiler will generate a symbol referring to some function (it doesn't see yet), but since the function is nowhere used, it won't complain. If you add this code, it will:

e1.f();// since e1 is a function, it has no member 'f' => compiler error

( as a sidenote: this code will also compile:

int a_function_prototype(int); // another prototype.
e1(); // should work!
a_function_prototype(5);

but after the compiler has finished, the linker will start looking for the actual function bodies, and won't find any.)

Now since the line

Example* e = new Example();

contains a keyword new the compiler recognises, and the it knows it can only be found in allocation+construction of a new object, it will generate code to do so.

xtofl