到目前为止,在我的计算机科学课程中,这是我们被告知要做的全部事情。不仅如此,这也是我们被允许做的所有事情,否则我们的代码会受到惩罚。我了解,通过查看在线发布的代码,您可以使用::std或std::来完成相同的事情。
我的问题是一般性的为什么?显然,为了学习者和简单起见,使用全球宣言更简单,但收回的是什么?在现实世界中期望::std更现实吗?我想补充一下,使用声明背后的逻辑/概念是什么?在我的课程中没有解释过这些,我想更好地理解它。
作为一个普遍的问题:如果我还没有教过这些内容,向量,模板,类,或错误处理似乎我错过了很多重要的C++功能吗?
事先谢谢!
- 我建议您花点时间阅读这个问题及其各种已发布的答案。这里可以看到一个很好的例子,在这种情况下,using namespace std;无辜地坐在某个翻译单元中,产生了意想不到的后果。值得一读。
- 谢谢,我去看看!我试图事先找到一些例子,但很多例子都像是"是的,有时会引起问题",没有证据。
- 不加区别地使用using namespace ...是一种不好的做法,它会导致许多微妙的、难以发现的错误。它绕过了将名称空间引入laguage的全部原因。也就是说,当using namespace ...的作用域受到限制(通过名称空间或本地作用域)时,它有适当的用途。尽管如此,std名称空间非常大,包含许多通用符号,因此我总是避免using namespace std。还可以看到:C++常见问题解答
- 我明白了,我不知道(在问这个问题之前)你可以在函数内部使用它,并且假设它只在全局空间中工作。
- 但是我要补充一点,做你的CS教授告诉你的,但是不要接受任何一个人告诉你的福音。学习最佳实践是一个持续的过程,多年来,您将从许多不同的人那里学习到这些实践。(即使这样,人们仍然会为其中的一些争论,呵呵)。
- 是的,我想这主要是我想要的。我只想尽可能做好准备。是的,我试着对她的教学风格保持开放的心态,因为她告诉我们总是选择数组而不是向量。
- 这让我很不安,教授教我怎么做,惩罚你不做,也不说为什么。using关键字有可能导致很多问题;我尽量不使用它(这是的,在大多数情况下意味着非常冗长的代码)。
这确实是你可以在啤酒里讨论几个小时的事情之一,但仍然没有一个大家都满意的答案。
如果您几乎总是使用std::功能,那么在文件开头添加using namespace std;并不是一个坏主意。另一方面,如果您使用多个命名空间中的内容(例如,使用llvm::编写编译器,同时使用std::编写编译器),可能会混淆哪些部分是llvm的一部分,哪些部分是std::的部分,因此在我的编译器项目中,我没有using namespace ...;的单个文件,而是编写llvm::和std::根据需要。有几个函数(可能是不明智的)称为Type(),有些地方使用something->Type()->Type()来获得我需要的类型。是的,有时甚至让我有点困惑…
我还有很多东西看起来像Constants::ConstDecl和Token::RightParen,所以我可以很快看到"什么是什么"。所有这些都可以缩短和"简化",但我更喜欢看到东西大部分时间都属于哪里。
更冗长的内容有助于更容易地看到事物的归属——但它有助于更多的打字和阅读,所以这是一种平衡。
- I don't have a single file with using namespace ...;+1;我知道很多开发人员(包括我自己)都喜欢这种方式。
- @为了清楚起见,当我快速修改一些代码以显示"这是如何完成的"(例如这里),我可能会使用using namespace std;。但对于我的编译器项目和其他更大的项目,我没有。
- 当然,这是明智的。
我个人不喜欢使用声明。对我来说,它们使代码不可读,并且破坏了名称空间。作为一名维护程序员,我已经花了20年的时间,我讨厌任何使代码难以阅读的东西——在我看来,使用和抛出规范一样无用。
更容易理解的是6个月——一年——10年
1 2 3 4
| UDP::Socket sock
sock.send(data)
TCP::Socket sock2
sock2.send(data) |
VS
1 2 3 4
| using UDP;
using TCP;
sock.send(data)
sock2.end(data) |
我也不喜欢名称空间别名
1
| using namespace po = boost::program_options; |
现在,您要让下一个程序员更努力地工作,通过一个额外的间接级别来查找与boost::program_选项相比,po是什么。同样的情况也发生在
四字的大小是多少?长4个字节有多长?在我的操作系统上8字节或17字节
我最后要做的是,如果你不能打字,那就不要当程序员——一个已保存的击键!=良好的可维护代码
general why?
命名是软件开发中比较困难的方面之一。初学者根本不知道他们的名字选择以后会如何产生歧义。
特别是,我们的软件行话经常对某些问题使用首选术语。这些首选项可能会导致不相关的类实例使用具有相似含义的相同(或类似)符号进行开发。
我经常使用的一些符号包括init()、exec()、load()、store(),我在很多地方使用timestampget()。我还使用open()、close()、send()/recv()或write()/read()。
所以,我可以在3个名称空间中的每个空间中重命名in it(),并在其中添加了5个对象,但是指定我想要的对象要简单得多。我在2个名称空间和12个对象中找到exec()。我使用了3种不同的timestampget()方法。无论是名称空间、函数还是类方法,这些符号对我来说都是有意义的。
此外,我发现5个字符的"std::"名称空间作为前缀是完全自然的,比全局的"使用名称空间std"更可取。我想这是练习的结果。
还有一个项目——任何一个较大的名称空间或类名变得令人厌烦的地方,我有时会添加一个typedef短名称…以下是一些生产代码示例:
1 2 3
| typedef ALARM_HISTORY ALM_HST;
typedef MONITOR_ITEM MI
typedef BACKUP_CONTROL BC; |
在一个团队中,我们同意使用定义明确的"全名",因为篇幅太长,有时会让人感到厌烦。在项目的后面,我们同意typedef(用于短类或名称空间名称)可以在简单的情况下使用,并且不会增加混淆。
- 这有点超出我的想象,但我想我至少得到了关于我的问题的前提,谢谢!
我想说的是,一般来说,你不会在全球范围内宣布使用性病。我想如果你只是做一个简单的申请,那就足够了。但是,在大型组织中工作时,经常会使用不同的名称空间,这些名称空间可能有重叠的对象。如果您在std和您创建的名称空间中有一个函数,然后调用"using namespace std"和"using namespace yournamespace",那么在调用该函数时会得到不需要的结果。当您为每个调用加上名称空间前缀时,它会使其更清晰,并且不会出现重叠问题。
- 型但是,如果您仍然希望ADL工作的话,用名称空间对每个调用进行前缀并不是一种可行的方法。考虑到using namespace std; template void Foo(T &a, T &b) { swap(a, b); },您如何更改对swap的调用以继续允许'namespace N { struct S { }; void swap(S &, S &); }',其中Foo应调用N::swap,而不是std::swap?
- 型为此,您确实需要using,但是您可以将其限制为您想要的那些函数,而不是所有namespace std。
- 型那么,名称空间是否有点像正在执行的"place"?就像标准的只是屏幕I/O?通过查看库中的一些函数定义,我看到了类似于其他::xxx空格的内容,并假定它们用于文件I/O或程序到程序I/O之类的内容?如果我错了,请纠正我,因为这对我来说都是无底洞。
- 型@用户3857017标准库将几乎所有内容直接放在std中。(标准库的特定实现在内部使用额外的名称空间,但这些是特定于实现的细节,通常不用于程序的直接使用。)文件访问、线程、容器,它们都是std名称空间的一部分。它的组织方式可能有所不同,包括用于文件访问的单独名称空间、用于容器类型的单独名称空间等,而其他一些库确实采用这种方法,但标准库没有。
- 型@用户3857017您可能看到的是类成员访问,它使用与命名空间成员访问相同的语法。给定A::B::C,A可以是命名空间或类,如果是命名空间,B可以是命名空间或类。没有办法仅仅从语法上判断,你必须查名字。是的,在某种程度上,类似这样的类可以用作某种名称空间,但不完全是。
- 型那么名称空间究竟提供了什么?它是一组分类还是"箱"来分类信息?这里有人提到你可以自己做,所以我想你可以根据自己在空间或其他方面的具体需求来定制它?
- 型@我想我真的不知道一门课是什么(是的,现在我感觉好像什么都没教过一样),所以我不能真正区分这两门课。但似乎很有可能。尽管大多数都是单独使用A::Std::然后使用常规COUT、CIN等。
- 型@用户3857017啊,好的。简短的回答:名称空间只是一种分组名称以防止冲突的方法。如果您有一个函数f()和另一个函数f(),在没有名称空间的语言中,您只会遇到无法解决的冲突,而不重命名其中一个函数。在具有名称空间的语言中,定义函数的人可以选择将其放在单独的名称空间中,如果这两个函数不在同一名称空间中,则不会发生冲突,这些函数可以共存。如何使用名称空间取决于定义函数的人员。
- 型@user3857017或:名称空间用于命名文件的目录。
- 型@hvd现在很有意义,谢谢你的清理。所以假设我们继续目录/文件的类比,它会变成library/namespace/function吗?或者命名空间是在头中定义的?(不好意思,如果这个话题偏离主题,我很感兴趣,我的书也不满意。)
- 型@用户3857017不,它只是名称空间/函数,由库来选择不太可能冲突的名称空间。标准库使用将大部分内容放在名称空间std中,并将一些内容放在全局名称空间(根目录)中。Boost是一个众所周知的和广泛使用的C++库,它把大多数事物放在命名空间EDCOX1(16)中。但是一个随机的第三方库也可能有一个(坏的?)把东西放在同一个名称空间boost中的原因。使用健全的名称空间取决于库,就像程序安装人员不直接在C:中安装所有内容一样。
- @我想我现在明白了。为了更好地理解它,我必须尝试从早期重新访问我的搜索。或者现在我可以问我的教授这个问题,实际上我有一个工作点。你帮了大忙!谢谢!
- @用户3857017对于名称空间,我听到的最好定义是它是函数和对象的逻辑分组。因此,std::namespace包含标准对象和函数,例如stl容器、std::fill_n()、std::max()、std::sort()等。同样,boost::namespace是boost库中的所有内容,而获取非常具体的boost::asio::ip::tcp::是处理boost::asio::lib中的tcp连接的对象和函数。拉里。
- @用户3857017举一个非常具体的例子,我工作的服务器有一个System名称空间,其中包含操作系统特定的例程。System::Sleep(int microseconds)需要一段时间,以微秒为单位,并能睡那么久。通过将它放在一个名称空间中,我们可以避免与win32中的Sleep()例程发生冲突,后者以毫秒为单位。所以我们在代码中从不使用Sleep()或::Sleep(),因为它不会在linus下用gcc编译,而是只使用System:Sleep()。
- @从理论上讲,下面的This::foo() That::foo() These::foo() Those::foo()和所有foo()调用在理论上会根据它们在每个名称空间中的定义产生不同的结果,这多少有些不负责任?
- 这是非常正确的。我也不会说这是不负责任的。正如您可能拥有类函数一样:Square::Draw()、Circle::Draw()、Triangle::Draw(),每个函数都有不同的功能,在您的示例中,不同的foo()例程可以做不同的事情。诀窍是知道何时使用C++的这个特性。如果使用得当,它会有完美的意义。boost::asio::ip::tcp::socket::send()和boost::asio::ip::udp::socket::send()就是这样一个例子,其中有两个send()方法,仅根据它们所在的名称空间进行区分。
- @user3857017"那么名称空间究竟提供了什么?"上面我还没有看到的一个重要区别是类和结构必须在一个编译单元(即.hpp文件)中定义。名称空间更为"开放",可以在多个文件中提供。例如,我的命名空间"dtb"在~30.hpp文件中定义了~50个类…就像"std"有很多类一样。当我阅读带有"dtb::"前缀的代码时,我知道在哪里可以找到(忘记了?)细节。