开发者

Difference between creating object with () or without

i just run into the problem

error: request for member ‘show’ in ‘myWindow’, which is of non-class type ‘MainGUIWindow()’

when trying to compile a simple qt-application:

#include <QApplication>
#include "gui/MainGUIWindow.h"


int main( int argc, char** argv )
{
  QApplication app( argc, argv );


  MainGUIWindow myWindow(开发者_运维问答);
  myWindow.show();


  return app.exec();
}

I solved this by replacing

MainGUIWindow myWindow(); 

by

MainGUIWindow myWindow;

but I don't understand the difference. My question: What is the difference?

Regards, Dirk


The other answers correctly state that the parentheses version is actually a function declaration. To understand it intuitively, suppose you wrote MainGUIWindow f(); Looks more like a function, doesn't it? :) The more interesting question is what is the difference between

MainGUIWindow* p = new MainGUIWindow;

and

MainGUIWindow* p = new MainGUIWindow();

The version with parentheses is called value-initialization, whereas the version without is called default-initialization. For non-POD classes there is no difference between the two. For POD-structs, however, value-initialization involves setting all members to 0,

my2c

Addition: In general, if some syntactic construct can be interpreted both as a declaration and something else, the compiler always resolves the ambiguity in favor of the declaration.


The following:

MainGUIWindow myWindow();

declares a function that takes no arguments and returns MainGUIWindow. I.e. myWindow is a function name.

MainGUIWindow myWindow;

on the other hand creates an object myWindow of type MainGUIWindow.


The difference is, that

MainGUIWindow myWindow(); 

declares function myWindow, which takes no parameters and returns MainGUIWindow, whereas

MainGUIWindow myWindow; 

creates new object of type MainGUIWindow, calling it's default constructor.


There is no real problems with the situation you have described. You remove the parentheses and bingo! it works.

The "most vexing parse" is a much bigger issue when it takes a single parameter and you want to pass in a temporary, eg

class Foo
{
public:
 explicit Foo( const Bar& bar );
};

Foo foo( Bar() );

will not create an instance of a Foo but will also declare a function that takes a function-pointer, and this one really does often sting you.


One of the guidelines for C++ compilers, in order to resolve code ambiguities, is: when something can be a function declaration, it is a function declaration. So when the compiler sees:

MainGUIWindow myWindow();

It understands you are declaring a function called myWindow, that takes no parameters and returns a MainGUIWindow. Obviously this is not what you want.

Just remove the parenthesis and you will be fine:

MainGUIWindow myWindow; // Create an object called myWindow, of type MainGUIWindow


In C++ every expression that looks like a function declaration is a declaration of a function. Consider more complex sample that in your question:

#include <iostream>

struct X
{
  X( int value ) : x(value) {}
  int x;
};

struct Y
{
  Y( const X& x ) : y(x.x) {}
  int y;
};

int main()
{
  int test = 10;
  Y var( X(test) );                 // 1
  std::cout << var.y << std::endl;  // 2

  return 0;
}

At first glance (1) is a declaration of the local variable var which should be initialized with a temporary of a type X. But this looks like a function declaration for a compiler and you will get an error in (2):

 error: request for member ‘y’ in ‘var’, which is of non-class type ‘Y(X)’

The compiler considers that (1) is the function with name var:

Y                var(             X                     test            );
^- return value  ^-function name  ^-type of an argument ^-argument name

Now, how to say to the compiler that you do not want to declare a function? You could use additional parentheses as follows:

Y var( (X(test)) );  

In your case MainGUIWindow myWindow() for the compiler looks like function declaration:

MainGUIWindow    myWindow(        void                  )
^- return value  ^-function name  ^-type of an argument


Also, from CppCon 2017: Louis Brandy “Curiously Recurring C++ Bugs at Facebook”

std::unique_lock<std::mutex> (_mutex);

Is a declaration of a lock named "_mutex" that locks nothing. Since you typically don't need to interact with locks later, it's very easy to miss giving it a name.

This is a problem for any RAII object that has both a default constructor and a more useful constructor that takes one argument.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜