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.
精彩评论