【问题标题】:How is this possible to use in c++?这怎么可能在 C++ 中使用?
【发布时间】:2013-10-15 13:08:29
【问题描述】:
  1. 令我惊讶的是,我发现 c++ 对象的名称可以与类名相同。有人可以向我解释原因吗?
  2. 当我将a 类的对象声明为a a1() 时,它不会引发错误,但不会调用构造函数。为什么会这样?

我的代码:

#include<iostream>
using namespace std;

class a 
{
    public:
    a() 
    {
        cout << "in a\n";
    }
};

int main()
{
    a a1();
    a a;
}

【问题讨论】:

  • a1 不是一个对象,而是一个函数。
  • 不是“最令人头疼的解析”。它只是一个函数声明。 most vexing parse 涉及带有临时参数的函数调用。
  • @PeteBecker 技术上是正确的,但我们没有单独的somewhat-vexing-parse 标签;)
  • @FredOverflow - 虽然问题应作为重复项关闭,但不应将其链接到与问题无关的答案,即使没有合适的标签。
  • @PeteBecker 我怀疑我们会找到涵盖他两个问题的副本。

标签: c++ class function-declaration variable-initialization


【解决方案1】:

这是我尝试使用clang 编译它时从你的代码中得到的,我认为它说明了一切。

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.

【讨论】:

    【解决方案2】:

    如果您查看C++draft standard section 3.3.10 名称隐藏 段落,实际上用变量隐藏类的名称是有效的2 说(强调我的):

    类名 (9.1) 或枚举名 (7.2) 可以被同一作用域中声明的变量、数据成员、函数或枚举器的名称隐藏。如果一个类或枚举名称和一个变量、数据成员、函数或枚举器在同一范围内(以任何顺序)以相同名称声明,则无论变量、数据成员、函数或枚举器名称是 可见。

    我认为这不是一个好的做法,而且会导致代码难以维护。这行代码其实是在声明一个函数:

    a a1();
    

    您也可以使用这个 pre-C++11

    a a1 ;
    

    或在C++11中引入的uniform initialization

    a a1{} ;
    

    回到名称隐藏,我惊喜地发现clang 会使用此代码警告您,无论设置的警告级别如何:

    int main()
    {
       a a;
       a a2 ;
    }
    

    我收到这条消息:

    main.cpp:12:10: note: class 'a' is hidden by a non-type declaration of 'a' here
       a a;
         ^
    

    虽然我看不到来自gcc 的类似警告。

    更新

    想到我之前在warts of uniform initialization 上制作的这个cmets,我意识到如果您怀疑a1 不是正确的类型,您可以使用typeid 来调试正在发生的事情。例如这段代码:

    std::cout << typeid(a).name() << std::endl ;
    std::cout << typeid(a1).name() << std::endl ;
    

    Coliru live example 上产生此输出:

    1a
    F1avE
    

    并将其传递给c++filt,您会收到以下输出:

    a ()     // A function that returns type a
    a        // type a
    

    【讨论】:

      【解决方案3】:

      当您编写a a1(); 时,它实际上被解析为函数声明,而不是对默认构造函数的调用。

      a a1;

      会正确调用默认构造函数

      当您编写a a; 时,它会起作用,因为在所谓的名称隐藏中,变量名优先于类名,但即使它起作用,它也只会导致混乱,我会避免这样做。

      对于所有喜欢标准引用的人来说,你去吧

      类名 (9.1) 或枚举名 (7.2) 可以被同一作用域中声明的变量、数据成员、函数或枚举器的名称隐藏。如果一个类或枚举名称和一个变量、数据成员、函数或枚举器在同一范围内(以任何顺序)以相同名称声明,则无论变量、数据成员、函数或枚举器名称可见。

      【讨论】:

      • “是的,它有效......” 没有解释。我本来希望是这样的:变量a 的本地定义隐藏了类型名称以避免干扰外部(包含)名称。
      • @Nobody 我不喜欢为每个简单问题引用标准,这也不是主要问题
      • 我没有说要引用标准(尽管有一个明确的权威答案总是很好的)。像我的评论中的一些推理就足够了。
      • @Nobody 挑剔的人保持这个网站的高质量:)
      • @Nobody Answers 不仅应该适用于 OP,还应该适用于未来的读者,因此要求更完整的答案绝不是一件坏事。不是每个人都喜欢引用标准,这没关系。
      【解决方案4】:

      a a1(); 是函数声明返回类型为a,与调用构造函数无关

      a a ; 是简单的语句工作正常会调用构造函数

      【讨论】:

        【解决方案5】:

        a a1(); 是一个函数声明。

        这是在 C++11 中创建统一初始化的一个重要原因。要使用 C++11 中的构造函数初始化对象,请使用 a a1{};

        【讨论】:

        • @PeteBecker 也统一初始化也有它自己的缺点,我们可以看到here
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-01-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-25
        相关资源
        最近更新 更多