extern const 默认构造对象

extern const default constructed object

这是我的代码

#include <iostream>
using namespace std;

class Q
{
public:
    Q() { cout << "constructor" << endl; }
};

extern const Q t/*()*/; //A
const Q s/*()*/; //B

int main()
{
    const Q t/*()*/;
}

我希望标记为 "A" 的行表示我正在创建类型为 Q 的对象 t,其链接是外部的,并且其字段不能被修改。创建是由构造函数完成的,没有参数,我已经提供了。

在 main 中,我希望以相同的方式创建 Q 类型的本地 t 对象,尽管它的链接必然只是这个文件,事实上,它的范围和持续时间将只针对 main。

C++ 允许我在 const Q t/()/ 中放置或不放置括号;在主要。在全局范围内,在A行我可以放或不放括号,并且构造函数不会被调用。

在 B 行中,我只允许不放置括号,否则,如果我定义函数原型,编译器会感到困惑。

我的问题是:

  1. 为什么我允许在//A行中放()或不放()的灵活性,考虑到在//B行中不存在这种灵活性?

  2. 无论我在1.中选择什么,我发现"constructor"不是在A行打印,即使它在B行打印。为什么?对此我真的不抱什么期望。一方面,打印它是合理的,因为我们在 main 中看到 C++ 理解调用 0 参数构造函数,即使没有括号。另一方面,如果是这种情况,那么我将如何进行 class 类型的非定义声明?

带有 extern 关键字的对象声明不是定义,除非它包含显式初始化程序。您尝试使用 () 来强制定义是朝着正确方向迈出的一步。但是,它失败了,因为这种带有 () 的声明会产生句法歧义,解决这个问题有利于 函数声明 ,而不是对象声明。

这同样适用于您的所有声明,而不仅仅是您似乎相信的 B。为什么你声称 B 行的 "this flexibility does not exist" 我不清楚:你可以在 B 行中包含 () 或省略它。在任何一种情况下,声明都是完全有效的,除了 () 它将声明一个函数。 (即不仅仅是"flexibility",而是非常剧烈的质变。)

对于 B 行,问题实际上是 non-existent,因为 B 行不使用 extern 关键字。没有 extern 行 B 是一个对象 definition 无论您是否使用显式初始化程序。在您的情况下,保持原样(没有 ())仍然会触发默认构造,就像您想要的那样。 main.

内部的局部声明也是如此

另一方面,A 行是有问题的,因为为了强制定义,您需要一个显式初始化程序,但是 () 并没有按照您的意愿执行。

为了在 "classic" C++98 中解决这个问题,您将被迫使用

extern const Q t = Q();

确保您正在创建由默认构造函数初始化的对象定义的语法。 (迂腐地说,它实际上是默认构造,然后是复制构造,但这是我们在 C++98 中不得不忍受的东西)。

在现代 C++(C++11 及更高版本)中,您可以使用 {} 初始化程序

将其变成一个定义(使用默认构造)
extern const Q t{};

extern const Q t = {};

由于显而易见的原因,基于 {} 的语法不会对函数声明产生任何歧义。