

文章目录
相信大部分在学校学习过C++的同学你们的老师一定会和你们说:现在要写C++的代码了,要换一下头文件用#include <iostream>,后面还要带上一个using namespace std;对于前一个头文件的包含和C语言中一样,若是需要使用对应库函数的话就要包一下这个头文件,但是你真的清楚后者吗?
今天我们就来聊聊有关C++中命名空间相关内容,带你好好见识一下什么叫做【命名空间】,并且带着
using namespace std;到底是什么的问题好好地探索一番🔍
有关命名空间的说法,我们要先从命名冲突讲起
#include <stdio.h>
#include <stdlib.h>
int rand = 0;
int main(void)
{
printf("rand = %d\n", rand);
return 0;
}
rand()函数发生了冲突
<stdlib.h>中的,而我们上面刚好包含了这个头文件,在程序环境和预处理章节,有提到过对于头文件而言是会在预编译(预处理)阶段展开的,所以便会展开对rand()这个函数的定义,因而和我们定义的rand变量发生了冲突
那要怎么去解决这个冲突呢?此时就可以使用到【namespace】命名空间了
::,或者使用using关键词来简化命名空间中名字的使用在介绍namespace命名空间之前,我们先来看一个东西叫做【域作用限定符】
我通过下面这个代码来向你演示💻
int a = 0;
void f1()
{
int a = 1;
printf("a = %d\n", a);
}
void f2()
{
int a = 2;
printf("a = %d\n", a);
}
int main(void)
{
f1();
return 0;
}


::,这个就叫做域作用限定符,因为这个符号的左边是空的,代表的就是全局域,所以会直接到全局去寻找这个变量a,此时打印出来的就不是这个1了,而不是0,这也就做到了访问当前局部作用域外的内容有了域的概念之后,我们再去学习命名空间就好多了,一起来看看吧👀
在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的
首先我们来看一个示例,也就是上面的那个rand变量的冲突
namespace r
{
int rand = 0;
}

不过有同学会疑惑函数不是要加上()吗,为何这里的rand就可以直接调用这个函数了呢❓

int(__cdecl *)(void)而言其实是一个函数指针,它指向了这个函数的地址,又刚好因为这个函数我们不需要传入参数,void表示无参,所以也相当于是调用了这个库函数【__cdecl是VS函数名修饰规则,我在函数重载会讲到】
同样,我们再通过一个示例来了解一下命名空间的概念
.h的头文件,里面分别有队列和单链表的结构体,不过对于它们来说我都将结点的结构体名称定义成了Node,此时我若是在.cpp的源文件中同时包含了这两个头文件就会出现问题❌
#include "Queue.h"
#include "List.h"
int main(void)
{
struct Node* qu;
struct Node* l;
return 0;
}

namespace Queue
{
//队列结构体...
}
namespace SingleList
{
//单链表结构体...
}

既然说了这是一个命名空间,那么在一个空间中就可以有很多的内容,而不仅限于一个普通的变量
namespace r
{
int rand = 0;
int GetMax(int a, int b) //函数
{
return a > b ? a : b;
}
struct Node { //结构体
struct Node* next;
int val;
};
}
namespace r
{
int rand = 0;
int GetMax(int a, int b)
{
return a > b ? a : b;
}
struct Node {
struct Node* next;
int val;
};
namespace r2
{
int c;
int d;
int Sub(int left, int right)
{
return left - right;
}
}
}
List.h和Queue.h的时候会出现什么情况呢?test.cpp中包含了这两个头文件的话两个命名空间中的内容会自动进行一个合并,也就是node这个命名空间中会有两个结构体,但是这个无法调试观察,所以不做过多解释
知道了命名空间该如何去定义,现在我们来说说如何去访问定义出来的命名空间的内容
【使用格式】:命名空间名称::成员
namespace Queue
{
struct Node {
struct Node* next;
int val;
};
//...
}
namespace SList
{
struct Node {
struct Node* next;
int val;
};
//...
}

Queue::Node和SList::Node,也就需要使用到上面所讲的【域作用限定符 :: 】
⚠切记,不要像下面这么去用,因为是Node冲突了,而不是struct这个关键字冲突了
Queue::struct Node qu;
SList::struct Node sl;
Queue::InitQueue(&qu);
Queue::Push(&qu, 1);
Queue::max = 200;
SList::PushBack(&sl, 1);
SList::PopBack(&sl);
SList::max = 300;
但是你不觉得这样很繁琐吗?对于一个队列或者是链表来说,初始化可能就使用到一次,但是入队和尾插就会被频繁使用到,此时我们就可以使用到
using关键字来进行一个部分展开了
【使用格式】:using 命名空间名称::成员
using声明引入的名字的作用域满足一般的作用域规则:有效范围从using声明的地方开始,到其语句所在的作用域结束时为止
using Queue::Push;
using SList::PushBack;
using SList::PopBack;

using namespace std;,因为他们都定义在了标准库中,只是包含头文件<iostream>是不够的#include <iostream>
int main(void)
{
std::cout << "hello namespace" << std::endl;
std::cout << "hello namespace" << std::endl;
std::cout << "hello namespace" << std::endl;
std::cout << "hello namespace" << std::endl;
return 0;
}
using std::cout;
using std::endl;

在我们做项目的时候,就是使用上面的这两种方式配合使用,要频繁使用到std标准库或者自己定义的命名空间中的内容,那就定义在程序开头,若是不常用的就在代码行中指定访问一下
【使用格式】:using namespace 命名空间名称::成员
using namespace Queue;


总结一下:
日常在做练习的时候,直接【全部展开】就可以了,方便使用;若是在做项目的时候,【指定展开】和【部分展开】配合使用,增加严谨性
最后再来对本模块所学习的命名空间做一个总的回顾
::的作用。对于两个头文件中的内容发生冲突时,就可以使用到namespace定义命名空间来进行一个封装,此时就不会发生冲突了最后,我们再来解答一下文章开头提出的问题,为何我们要去使用到
using namespace std这个东西呢❓相信在认真看完本文之后你心中一定也有了答案和自己使用时的取舍
#include <iostream>
using namespace std;
int main(void)
{
cout << "hello namespace" << endl;
return 0;
}
using namespace std;去掉之后,【cout】和【endl】就报出了错误,这是为何呢?
看完下面这些你就会清楚了👇
.h后缀的头文件中,使用时只需包含对应头文件即可,后来将其实现在std命名空间下,为了和C头文件区分,也为了正确使用命名空间,规定C++头文件不带.h;旧编译器(vc 6.0)中还支持<iostream.h>格式,后续编译器已不支持,因此推荐使用+std的方式可是呢,这种命名空间直接展开我是不推荐的,不仅是对于标准std中的内容,以及我们自己所定义的命名空间也是一样,但是你要了解为什么要使用它。
📖参考文献📖
2023年2月27日记,如有疑惑,请指出
我的问题很简单:我是否必须在使用RubyonRails的类上require'csv'?如果我打开一个railsconsole并尝试使用CSVgem它可以工作,但我必须在文件中这样做吗? 最佳答案 CSVlibrary是ruby标准库的一部分;它不是gem(即第三方库)。与所有标准库(与核心库不同)一样,csv不会由ruby解释器自动加载。所以是的,在您的应用程序中某处您确实需要要求它:irb(main):001:0>CSVNameError:uninitializedconstantCSVfrom(irb):1from/Us
我经常将预配置的lambda插入可枚举的方法中,例如“map”、“select”等。但是“注入(inject)”的行为似乎有所不同。例如与mult4=lambda{|item|item*4}然后(5..10).map&mult4给我[20,24,28,32,36,40]但是,如果我制作一个2参数lambda用于像这样的注入(inject),multL=lambda{|product,n|product*n}我想说(5..10).inject(2)&multL因为“inject”有一个可选的单个初始值参数,但这给了我......irb(main):027:0>(5..10).inject
是否有self验证的问题列表。看着那个,我可以确定我知道。我应该复习一下。在学习的过程中,我列了一个这样的list,但它只包含我在某处听说过的项目。我需要一段时间才能找到新的东西。 最佳答案 以下是针对ruby和Rails的一些测试列表。证书名称:RubyonRails谁提供:oDeskIncorporation认证费用:免费网站:https://www.odesk.com/tests/985?pos=0证书名称:RubyonRails提供者:Techgig.com(TimesBusinessSolutionsLimited(T
我想覆盖store_accessor的getter。可以查到here.代码在这里:#Fileactiverecord/lib/active_record/store.rb,line74defstore_accessor(store_attribute,*keys)keys=keys.flatten_store_accessors_module.module_evaldokeys.eachdo|key|define_method("#{key}=")do|value|write_store_attribute(store_attribute,key,value)enddefine_met
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我最近开始学习Ruby,这是我的第一门编程语言。我对语法感到满意,并且我已经完成了许多只教授相同基础知识的教程。我已经写了一些小程序(包括我自己的数组排序方法,在有人告诉我谷歌“冒泡排序”之前我认为它非常聪明),但我觉得我需要尝试更大更难的东西来理解更多关于Ruby.关于如何执行此操作的任何想法?
Ruby是完全面向对象的语言。在ruby中,一切都是对象,因此属于某个类。例如5属于Objectclass1.9.3p194:001>5.class=>Fixnum1.9.3p194:002>5.class.superclass=>Integer1.9.3p194:003>5.class.superclass.superclass=>Numeric1.9.3p194:005>5.class.superclass.superclass.superclass=>Object1.9.3p194:006>5.class.superclass.superclass.superclass.su
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。我一直在Rails上做两个项目,它们运行良好,但在这个过程中重新发明了轮子,自来水(和热水)和止痛药,正如我随后了解到的那样,这些已经存在于框架中。那么基本上,正确了解框架中所有智能部分的最佳方法是什么,这将节省时间而不是自己构建已经实现的功能?从第1页开始阅读文档?是否有公开所有内容的特定示例应用程序?一个特定的开源项目?所有的rails交通?还是完全
假设我有一个函数defodd_or_evennifn%2==0return:evenelsereturn:oddendend我有一个简单的可枚举数组simple=[1,2,3,4,5]然后我用我的函数在map中运行它,使用一个do-endblock:simple.mapdo|n|odd_or_even(n)end#=>[:odd,:even,:odd,:even,:odd]如果不首先定义函数,我怎么能做到这一点?例如,#doesnotworksimple.mapdo|n|ifn%2==0return:evenelsereturn:oddendend#Desiredresult:#=>[
我正在根据Rails指南的建议开发Rails应用程序,以创建包含翻译的文件夹树和文件。我的文件夹树与此类似:|-defaults|---es.rb|---en.rb|-models|---book|-----es.rb|-----en.rb|-views|---defaults|-----es.rb|-----en.rb|---books|-----es.rb|-----en.rb|---users|-----es.rb|-----en.rb|---navigation|-----es.rb|-----en.rbconfig/locales/views/books/en.yml中的内容
在以下示例中,我无法理解Ruby运算符的优先级:x=1&&y=2由于&&的优先级高于=,我的理解是类似于+和*运算符:1+2*3+4解析为1+(2*3)+4它应该等于:x=(1&&y)=2但是,所有Ruby源代码(包括内部语法解析器Ripper)都将其解析为x=(1&&(y=2))为什么?编辑[08.01.2016]让我们关注一个子表达式:1&&y=2根据优先规则,我们应该尝试将其解析为:(1&&y)=2这没有意义,因为=需要特定的LHS(变量、常量、[]数组项等)。但是既然(1&&y)是一个正确的表达式,那么解析器应该如何处理呢?我试过咨询Ruby的parse.y,但它太像意大利面条