为什么要使用extern关键字在命名空间范围内声明变量?

时间:2019-01-01 15:41:33

标签: c++ namespaces const definition extern

我对C ++还是很陌生,目前正在学习一门简短的课程。我有Java的背景。

我希望有一个名为“消息”的名称空间,该名称空间将用于存储不变的/不变的字符串,这些字符串将在整个程序的各种不同类中使用。 (例如标题,关键字,名称等)。

如果所有这些字符串都在一个类中,则它们将是const和static,因此,我认为最好将它们放入命名空间而不是类中。我当前的“ Message.h”看起来像这样:

#ifndef MESSAGE
#define MESSAGE

#include <string>

namespace Message {
    const std::string NAME = "Car";
    const std::string SEPARATE = " | ";
    const std::string COMMAND = "Please enter a 1, 2 or a 3: ";
};

#endif MESSAGE

直到教练建议我将其更改为此...

Message.h:

#ifndef MESSAGE
#define MESSAGE

#include <string>

namespace Message {
    extern const std::string NAME;
    extern const std::string SEPARATE;
    extern const std::string COMMAND;
};

#endif MESSAGE

Message.cpp:

#include "Message.h"

const std::string Message::NAME = "Car";
const std::string Message::SEPARATE = " | ";
const std::string Message::COMMAND = "Please enter a 1, 2 or a 3: ";

在课程结束之前,我几乎没有时间从讲师那里进行澄清,而且还需要一段时间才能获得机会。根据我的研究,它与翻译单元有关,更具体地说,是尝试在其他翻译单元中使用变量。

我了解这的一般概念,但是我不能完全理解在这种情况下使用extern的好处?

这里包含的保护措施是否不足以使Message ::名称空间变量不会被声明/定义多次?为什么在这种情况下建议使用extern关键字,而这纯粹是出于编译速度的好处?

1 个答案:

答案 0 :(得分:3)

两者都可以正常工作(尽管问题已引起人们的广泛质疑)。区别有点微妙。

在第一个示例中,每个包含该标头的翻译单元(认为.cpp文件)都将获得这三个字符串中每个字符串的副本。可以这样做,因为它们被标记为const,因此它们不会从翻译单元中导出。如果它们不是const,则您将具有相同符号的多个定义。

在第二个示例中,三个字符串中的每个字符串都只有一个副本。这些副本位于Message.cpp中,并将链接到您的可执行文件中。任何包含Message.h的翻译单元都将知道这些名称,因为它们是在标头中声明的,并且可以使用它们。

对于诸如常数int之类的小事情,第一种方法最常见。对于较大的事物,例如字符串对象(通常需要非平凡的初始化的事物),第二种方法是最常见的。