【问题标题】:Difference between creating object with () or without使用 () 或不使用创建对象的区别
【发布时间】:2011-02-25 11:15:25
【问题描述】:

我只是遇到了问题

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

当尝试编译一个简单的 qt 应用程序时:

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


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


  MainGUIWindow myWindow();
  myWindow.show();


  return app.exec();
}

我通过替换解决了这个问题

MainGUIWindow myWindow(); 

通过

MainGUIWindow myWindow;

但我不明白其中的区别。我的问题:有什么区别?

问候, 德克

【问题讨论】:

标签: c++ qt most-vexing-parse


【解决方案1】:

其他答案正确地指出括号版本实际上是一个函数声明。为了直观理解,假设你写了MainGUIWindow f(); 看起来更像是一个函数,不是吗? :) 更有趣的问题是两者有什么区别

MainGUIWindow* p = new MainGUIWindow;

MainGUIWindow* p = new MainGUIWindow();

带括号的版本称为值初始化,而没有括号的版本称为默认初始化。对于非 POD 类,两者之间没有区别。然而,对于 POD 结构,值初始化涉及将所有成员设置为 0,

my2c

补充:一般来说,如果某些句法结构既可以解释为声明,也可以解释为其他内容,编译器总是会解决歧义以支持声明

【讨论】:

  • 这被称为“最麻烦的解析”。
  • 当您尝试创建一个接受一个成员的类的实例并传入您认为是临时的,尤其是当它具有隐式构造函数时会出现问题时,会出现更麻烦的解析
  • Con-rats 和其他啮齿动物跨越 10k 障碍,但这是一个骗局。我想那里有很多“最令人头疼的解析”问题。 (我标记了第一个看起来匹配的。)
【解决方案2】:

以下内容:

MainGUIWindow myWindow();

声明一个不带参数并返回MainGUIWindow的函数。 IE。 myWindow 是一个函数名。

MainGUIWindow myWindow;

另一方面,创建myWindow 类型的对象MainGUIWindow

【讨论】:

    【解决方案3】:

    不同的是,

    MainGUIWindow myWindow(); 
    

    声明函数myWindow,它不接受任何参数并返回MainGUIWindow,而

    MainGUIWindow myWindow; 
    

    创建MainGUIWindow 类型的新对象,调用它的默认构造函数。

    【讨论】:

      【解决方案4】:

      您所描述的情况并没有真正的问题。你删除括号和宾果游戏!它有效。

      当它采用单个参数并且您想传入一个临时参数时,“最令人头疼的解析”是一个更大的问题,例如

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

      不会创建 Foo 的实例,但也会声明一个带有函数指针的函数,而这个函数确实经常让你感到刺痛。

      【讨论】:

        【解决方案5】:

        为了解决代码歧义,C++ 编译器的指导方针之一是:当某些东西可以是函数声明时,它就是函数声明。所以当编译器看到:

        MainGUIWindow myWindow();
        

        它知道您正在声明一个名为 myWindow 的函数,该函数不接受任何参数并返回 MainGUIWindow。显然这不是你想要的。

        去掉括号就可以了:

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

        【讨论】:

          【解决方案6】:

          在 C++ 中,每个看起来像函数声明的表达式都是函数的声明。考虑您的问题中更复杂的示例:

          #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;
          }
          

          乍一看,(1) 是局部变量var 的声明,它应该使用X 类型的临时变量进行初始化。但这看起来像是一个编译器的函数声明,你会在 (2) 中得到一个错误:

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

          编译器认为(1)是名称为var的函数:

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

          现在,如何对编译器说你不想声明一个函数?您可以使用额外的括号,如下所示:

          Y var( (X(test)) );  
          

          在您的情况下,编译器的 MainGUIWindow myWindow() 看起来像函数声明:

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

          【讨论】:

            【解决方案7】:

            另外,来自 CppCon 2017:Louis Brandy “Curiously Recurring C++ Bugs at Facebook”

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

            是一个名为“_mutex”的锁的声明,它什么都不锁。由于您以后通常不需要与锁进行交互,因此很容易错过为其命名。

            对于同时具有默认构造函数和更有用的接受一个参数的构造函数的任何 RAII 对象来说,这都是一个问题。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-06-05
              • 2019-05-23
              • 1970-01-01
              • 2017-03-09
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多