声明一个类的常量实例

38

假设我有一个定义如下的类:

class foo{};

现在,这是完全可接受的;

foo f;

为什么会是编译错误?(未初始化的常量'f')

const foo f;

为什么我们必须要这样做?

const foo f = foo();

我知道我们为什么做不到这个...

const foo f(); // though it compiles..

有趣的是,以下代码是有效的:

const std::string f;

那么foo缺少什么?

我意识到那里有三个问题,这样做很不好,但我希望有人能在一个答案中为我解决这个问题。

编辑:如果这个问题很蠢,请随意关闭它...


6
顺便说一下,在Stack Overflow上我看到了很多愚蠢的问题。但是你的问题绝不是一个愚蠢的问题。 - Konrad Rudolph
@Konrad Rudolph,我坐在那里挠头,通常这种情况发生在我做了一些愚蠢的事情时... :) - Nim
4个回答

48

你的类是一个POD(基本上是因为它没有提供默认构造函数)。POD变量在声明时不会被初始化。也就是说,以下代码:

foo x;

代码不会将x初始化为有意义的值,这必须单独完成。现在,当您将其声明为const时,可能永远不会发生这种情况,因为您无法再分配或更改x

考虑与int等价的情况:

int x; // legal
const int y; // illegal

正如你所注意到的那样,使用 std::string 而不是 foo 是可编译的。 这是因为 std::string 不是 POD。 解决你所面临的问题的一个简单方法是为 foo 提供一个默认构造函数:

class foo {
public:
    foo() { }
};

现在你的const foo x;代码可以编译。


@Konrad,真正有趣的是gcc是唯一一个报错的编译器。当我尝试使用其他编译器(如msvc、CodeGear和digital mars)时,它们都可以编译而没有任何抱怨。这种行为是否不符合标准? - greatwolf
@Victor:你真的确定 foo 类是一个 POD(即没有任何成员)吗?如果是这样,那么是的,那些编译器是不符合标准的编译器。这段代码不应该编译。 - Konrad Rudolph
@Konrad 是的,foo 只是一个空的结构体。我有一个带有和不带有默认构造函数的版本。我刚刚用 comeau 进行了测试,它也正确地捕捉到了这个问题。所以看起来只有 gcc 和 comeau 符合标准。 - greatwolf
@Nim:我也没有意识到,如果这能让你感到安慰的话,我想我还没有做足够的C语言练习... - Matthieu M.
@Victor T:你检查过编译标志了吗?MSVC因其对标准的扩展而闻名,它可能只是将结构体初始化为非POD。我无法回忆起它的“-pedantic”等效项,但也许你应该测试一下? - Matthieu M.

6
在空类的情况下引发错误是一个已知的问题,并报告为问题#253

1

const 应用于一个简单的 POD(Plain Old Data)变量,表示该变量在该上下文中不会改变 - 因此您将无法将其重新分配给其他内容。因此,您必须对其进行初始化,否则它将永久未初始化,从而无用。


应用于简单的普通数据变量,表示该变量在该上下文中不会改变。而对于非POD类型,这意味着更少吗?(提示:并不是) - curiousguy

1

我认为还有更多的选择。你可以做

const foo f={};

或者

const foo f(());

Const 意味着你不能在以后对它进行赋值,所以你必须初始化它。由于你没有定义默认构造函数,编译器会认为它必须由你来初始化。std::string 有默认构造函数,因此编译器会隐式调用它。


但是这两种形式通常不等价:第一种形式将初始化foo的所有成员为0(适当转换),而第二种形式将值初始化f:如果有默认构造函数,则调用默认构造函数,否则将值初始化每个成员:如果存在成员的默认构造函数,则调用该构造函数,或者如果它是一个聚合体,则值初始化聚合体的每个成员,或将成员初始化为0(适当转换)。 - curiousguy
const foo f(());” 不是有效的语法。 - gx_

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接