C++:“类命名空间”? [复制]

Posted

技术标签:

【中文标题】C++:“类命名空间”? [复制]【英文标题】:C++: "Class namespaces"? [duplicate] 【发布时间】:2011-05-03 04:59:39 【问题描述】:

如果在 C++ 中我有一个类 longUnderstandableName。对于那个类,我有一个包含其方法声明的头文件。在类的源文件中,我必须写longUnderstandableName::MethodAlongUnderstandableName::MethodB等等,无处不在。

我能否以某种方式使用命名空间或其他东西,这样我就可以在类源文件中写入MethodAMethodB,并且只写在那里?

【问题讨论】:

截至目前,答案是否定的。 但是...存在a proposal to add namespace class to the language,这将完全实现您和我想要的:在一个块中启用已声明的类成员的定义,该块将自动将它们限定为类 - 从而避免不断地重新输入类名范围、模板参数等。奇怪的是,它一直被采用到现在,这仍然只是在提案阶段,但我们到了。叹!我真的希望这可以使它成为 C++20 或其他任何东西。 @underscore_d 遗憾的是,该提案不包括 using class 等效项,因此它仍然不能提供完全的灵活性。 @negamartin 您还在寻找什么?请举个例子。重点是namespace class 将为课程作者解决此重复问题,这是 OP 提出此问题的角度。同时,该课程的用户可以执行using tiny_type = SomeNamespace::SomeOtherNamespace::AHugeClassName; 之类的操作。你还想要什么? @underscore_d 想象一个类中的枚举,GiganticallyLongClassName::CONSTANT1GiganticallyLongClassName::CONSTANT2等等。如果类是命名空间,我可以在函数using GiganticallyLongNamespaceName;中使用,但是因为这是一门课,我每次都必须输入GiganticallyLongClassName::CONSTANT1。使用using class 指令,using class GiganticallyLongClassName; 之类的指令会将其缩短为 CONSTANT1CONSTANT2 等……我认为没有理由不将其包含在提案中。 @negamartin I have to type GiganticallyLongClassName::CONSTANT1 every time. 好吧,不是真的:正如许多其他人指出的那样(尽管我认为回答的问题与所问的问题不同......)你可以做到using g = GiganticallyLongClassName; g::CONSTANT1; - 但我明白你在说什么。我认为其他地方有关于您想要的 using 扩展类型的建议,我不确定 [ahem] 是否在 namespace class 的范围内。 【参考方案1】:
typedef longUnderstandableName sn;

然后你可以定义方法为

void sn::MethodA() 
void sn::MethodB() 

并将它们用作

sn::MethodA();
sn::MethodB();

这仅适用于longUnderstandableName 是类的名称。即使该类被深深嵌入到其他命名空间中,它也能正常工作。

如果longUnderstandableName是一个命名空间的名字,那么在你要使用方法的命名空间(或源文件)中,可以写

using namespace longUnderstandableName;

然后调用类似的方法

MethodA();
MethodB();

你应该注意不要在头文件中使用using namespace foo;,因为这样会污染我们#include头文件进入的每个.cpp文件,但是在@987654332的顶部使用using namespace foo; @ 文件绝对是允许和鼓励的。

【讨论】:

真的有用吗?我的意思是 typedef 是制作缩写的救星,但声明通常需要原始名称。你用过这种方法吗? @Basilevs:声明不需要原始名称。 typedef 不会“创建一个与旧类型不同的新类型”——它只是创建一个引用相同旧类型的新名称。人们一直使用这种方法将std::map<std::string,std::string>::iterator 之类的内容翻译成更短的内容。 (而 std::map<std::string,std::string>::iterator 通常已经是 typedef 用于在 STL 中作为实现细节的某些类。 但这不是迭代器的声明。您引用的是在别处声明的类型迭代器的用法。 @Baslievs:看到某人typedef std::map<std::string,std::string>::iterator MapIt 是很常见的,这样他们就可以在循环中引用MapIt 类型并节省一些输入。在 C 中看到某人 typedef Foo* FooPtr 也很常见,虽然我不知道为什么人们认为这个 typedef 很有用。 @Basilevs 询问 typedef 是否可以在 定义 成员函数时使用,而不是在 使用 它们时使用,这是(我认为)原来的题。换句话说,下面的代码是否正确typedef longUnderstandableName sn; void sn::MethodA() ? (显然是这样。)【参考方案2】:

在类的方法中,你可以不加限定地使用名称,无论如何:只要去掉longUnderstandableName::前缀。

在类源文件中不是方法的函数中,我建议引入文件范围的静态内联函数,如下所示:

inline type MethodA(type param)
    return longUnderstandableName::MethodA(param);

那么就可以调用MethodA不合格了;由于内联性质,这可能不会产生任何运行时开销。

【讨论】:

是的,但这会强制您在标头中定义方法,这是低效的,因为它会在类更改时强制重新编译所有客户端。 不,它不会强迫你这样做。事实上,你不应该在头文件中定义方法,而是在类源文件的顶部 - 否则快捷方式将是全局可用的,这是 OP 不希望发生的。 仅适用于静态成员。 @Basilevs:当然,但是无论如何,OP 显然是在谈论静态成员,因为例如,他通常根本不需要键入类名来调用方法。 @Martinv.Löwis 相当肯定的上下文表明他们在谈论不合时宜的定义方法,这总是需要详细的全名。【参考方案3】:

我不确定我是否会推荐它,但您可以使用如下宏:

#define sn LongUnderstandableName

void sn::MethodA(parameters)  ... 
int sn::MethodB(parameters)  ... 

等等。宏的缺点之一是它们不尊重范围,但在这种情况下,您(显然)想要的范围是源文件,它恰好与宏的范围对应(非常接近)。

【讨论】:

+1,这是一个快速的解决方案,但我也不推荐它。这是灾难的秘诀。 是的——我更有可能在编辑器中将它定义为一个宏,所以我只需要输入短名称,它就会自动扩展为真正的名称——但没有人否则必须意识到这一点。 你可以使用 typedef。 -1 使 typedef 答案更好:) 虽然您可以改用typedef,并且在某些时候/情况下typedef 提供了真正的优势,但这似乎成为其中之一。对于这种情况,typedef 是一个等效的答案,而不是更好的答案。【参考方案4】:

嗯,是的,一旦你了解了命名空间。

不要将您的类命名为 MyBonnieLiesOverTheOcean,而是设置以下内容:

namespace My  namespace Bonnie  namespace LiesOverThe 
   class Ocean  ... ;
  

现在,在定义方法时,您在整个文件周围放置相同的命名空间,然后编写:

Ocean::SomeMethod() ...

当使用所有命名空间之外的类时,它是:

My::Bonnie::LiesOverThe::Ocean

如果您需要在某个源文件中从其他命名空间中引用很多东西,您可以使用“use”指令来去掉前缀。

【讨论】:

这是个好主意,但输入所有这些::) 一定很糟糕 嗯,这就是我们有“使用”的原因。 嗯,好的,是的。你可以说use My::Bonnie::LiesOverThe;然后在最后一个嵌套层工作 如果你真的想要,你可以在一些源文件中使用namespace mbl = My::Bonnie::LiesOverThe;,并将类引用为mbl::Ocean

以上是关于C++:“类命名空间”? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

C++ Primer 5th笔记(chap 18 大型程序工具) 类 命名空间与作用域

窗体头文件中的“错误 C2653:系统不是类或命名空间名称”,Visual C++

处理命名空间中的命名空间模型(类)

Python()-类命名空间和对象/实例命名空间

python基础 13 类命名空间于对象实例的命名空间,组合方法

类命名空间与对象实例的命名空间