extern const默认构造对象

时间:2017-01-27 21:32:16

标签: c++ class constructor extern

这是我的代码

#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类型的对象,其链接是外部的,并且其字段不能被修改。创建由没有参数的构造函数完成,我已经提供了。

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

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

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

我的问题是:

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

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

1 个答案:

答案 0 :(得分:0)

具有extern关键字的对象声明不是定义,除非它包含显式初始值设定项。您尝试使用()强制定义是朝着正确方向迈出的一步。但是,它失败了,因为()的这种声明会产生语法歧义,而这种歧义有利于函数声明,而不是对象声明。

这同样适用于您的所有声明,而不仅仅是B,因为您似乎相信。为什么你声称B行的“这种灵活性不存在”对我来说并不清楚:你可以在行B中加入()或省略它。在任何一种情况下,声明都是完全有效的,除了使用()它将声明一个函数。 (即,它不仅仅是一种“灵活性”,而是一种非常激烈的质变。)

对于B行,问题确实不存在,因为B行不使用extern关键字。如果没有extern,则无论您是否使用显式初始化程序,B行都是对象定义。在你的情况下,保持原样(没有())仍然触发默认构造,就像你想要的那样。这同样适用于main内的本地声明。

另一方面,

A行是有问题的,因为为了强制定义,您需要一个显式初始值设定项,但()不能达到您想要的效果。

为了在“经典”C ++ 98中解决这个问题,你将不得不使用

extern const Q t = Q();

语法,以确保您正在创建由默认构造函数初始化的对象定义。 (讽刺的是,它实际上是默认构造,然后是复制构造,但这是我们在C ++ 98中必须要考虑的事情。)

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

将其转换为定义(使用默认构造)
extern const Q t{};

extern const Q t = {};

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

相关问题