C++:“类命名空间”? [复制]
Posted
技术标签:
【中文标题】C++:“类命名空间”? [复制]【英文标题】:C++: "Class namespaces"? [duplicate] 【发布时间】:2011-05-03 04:59:39 【问题描述】:如果在 C++ 中我有一个类 longUnderstandableName
。对于那个类,我有一个包含其方法声明的头文件。在类的源文件中,我必须写longUnderstandableName::MethodA
,longUnderstandableName::MethodB
等等,无处不在。
我能否以某种方式使用命名空间或其他东西,这样我就可以在类源文件中写入MethodA
和MethodB
,并且只写在那里?
【问题讨论】:
截至目前,答案是否定的。 但是...存在a proposal to addnamespace class
to the language,这将完全实现您和我想要的:在一个块中启用已声明的类成员的定义,该块将自动将它们限定为类 - 从而避免不断地重新输入类名范围、模板参数等。奇怪的是,它一直被采用到现在,这仍然只是在提案阶段,但我们到了。叹!我真的希望这可以使它成为 C++20 或其他任何东西。
@underscore_d 遗憾的是,该提案不包括 using class
等效项,因此它仍然不能提供完全的灵活性。
@negamartin 您还在寻找什么?请举个例子。重点是namespace class
将为课程作者解决此重复问题,这是 OP 提出此问题的角度。同时,该课程的用户可以执行using tiny_type = SomeNamespace::SomeOtherNamespace::AHugeClassName;
之类的操作。你还想要什么?
@underscore_d 想象一个类中的枚举,GiganticallyLongClassName::CONSTANT1
、GiganticallyLongClassName::CONSTANT2
等等。如果类是命名空间,我可以在函数using GiganticallyLongNamespaceName;
中使用,但是因为这是一门课,我每次都必须输入GiganticallyLongClassName::CONSTANT1
。使用using class
指令,using class GiganticallyLongClassName;
之类的指令会将其缩短为 CONSTANT1
、CONSTANT2
等……我认为没有理由不将其包含在提案中。
@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++