1.前言:
如果要学习C++,必须是要有C语言的基础。C++基本上兼容C语言的语法,也就是说C语言的代码是可以在C++的环境中运行的。C++是C的一个超集,它在C语言的基础上增加了面向对象,泛型,同时去弥补C语言的不足。
2.命名空间
C语言的缺陷之一就是无法解决命名冲突的问题,比如函数名冲突,变量名冲突等等。在C语言里一旦出现了命名冲突这个问题,唯一方式就是去改其中一个名字。为了解决命名冲突这个问题,C++就出现了命名空间(namespace)。
2.1命名空间的定义
使用关键字namespace来定义一个命名空间,例如:
namespace dew
{
void func(int a)
{
a++;
}
int b = 20;
}
定义的方式类似于结构体,但是命名空间的后面不需要加上分号。里面可以放函数,变量,结构体等。
2.2访问命名空间中的成员
如果我们想访问命名空间中的成员,需要使用域作用限定符::,例如:
#include <stdio.h>
namespace dew
{
void func(int a)
{
a++;
}
int b = 20;
}
int main()
{
printf("%d\n",dew::b);
dew::func(10);
return 0;
}
2.3嵌套命名空间
命名空间还可以嵌套,例如:
namespace dew
{
int b = 20;
namespace dew1
{
int b = 10;
struct node
{
struct node* next;
int data;
};
}
}
如果我们要去访问嵌套命名空间的里面的成员时,需要使用多个域作用限定符,例如:
#include <stdio.h>
namespace dew
{
int b = 20;
namespace dew1
{
int b = 10;
struct Node
{
struct Node* next;
int data;
};
}
}
int main()
{
printf("%d\n",dew::dew1::b);
struct dew::dew1::Node node;
node.next = NULL;
node.data = 20;
return 0;
}
命名空间虽然可以多次的去嵌套,但是不建议套太多层。
2.4命名空间的定义和声明分离
如果我们要实现一个栈,为了解决命名冲突的问题使用了命名空间,但是要实现定义和声明分离该怎么去做呢?
多个文件相同名称的命名空间,它们会并在一起(同一个文件,相同名称的命名空间也会合并在一起,但是不建议在同一个文件下去定义两个相同名称的命名空间),如果我们实现的栈要声明和定义分离,例如:
1..h头文件
#ifndef __STACK_H
#define __STACK_H
#include <stdlib.h>
#include <stdio.h>
namespace Mystack
{
struct Stack
{
int* data;
int top;
int capacity;
};
void StackInit(struct Stack* s);
void StackPush(struct Stack* s,int a);
}
#endif
2..cpp源文件
#include "stack.h"
namespace Mystack
{
void StackInit(struct Stack* s)
{
s->data = (int*)malloc(sizeof(int)*4);
s->top = 0;
s->capacity = 4;
}
void StackPush(struct Stack* s,int a)
{
if(s->capacity == s->top)
{
//扩容
}
s->data[s->top] = a;
s->top++;
}
}
3.测试部分
#include "stack.h"
int main()
{
struct Mystack::Stack s;
Mystack::StackInit(&s);
Mystack::StackPush(&s,1);
Mystack::StackPush(&s,2);
Mystack::StackPush(&s,3);
return 0;
}
2.5命名空间的展开
我们要访问命名空间里的成员,每次都要使用域作用限定符去访问,这样做有些麻烦。我们可以使用关键字using来展开命名空间,展开后就可以不用使用域作用限定符也能访问命名空间里面的成员了。
1.全部展开
我们可以把命名空间给理解为一堵墙,里面的成员都被墙围了起来,我们要访问里面的成员都需要指定到对应的墙内去找,但是使用using展开命名空间后,这堵墙就不在了,就不用去指定访问了,例如:
#include <stdio.h>
namespace dew
{
void test()
{
printf("hello world\n");
}
int a = 20;
}
using namespace dew;//展开dew这个命名空间
int main()
{
printf("%d\n",a);
test();
return 0;
}
2.指定展开
命名空间还可以指定展开里面的成员,指定展开的成员就不需要使用域作用限定符去访问,但是未展开的成员还是需要使用域作用限定符去访问,例如:
#include <stdio.h>
namespace dew
{
void test()
{
printf("hello world\n");
}
int a = 20;
int b = 10;
}
using dew::a;
using dew::test;
int main()
{
printf("%d\n",a);
test();
printf("%d\n",dew::b);
return 0;
}
命名空间的展开和头文件的展开是不一样:
命名空间的展开:告诉编译器,除了在全局,也会在展开的命名空间里去搜索;
头文件的展开:在预处理阶段,将头文件的内容拷贝过来;
如果我们测试代码和代码量很小的情况下,嫌麻烦是可以去展开命名空间的。但是将来在公司里面,或者是项目很大的情况下是不建议去展开命名空间的,展开命名空间后可能又会造成命名冲突的问题。
2.6总结
1.定义命名空间的关键字:namespace;
2.要访问命名空间的成员需要使用域作用限定符::;
3.命名空间可以嵌套,但是不建议嵌套多层;
4.多个相同名称的命名空间,它们会合并在一起;
5.要展开命名空间,需要使用的关键字:using,不建议去展开命名空间,展开后可能又会造成命名冲突;
3.输入输出
我们在学习C语言中使用的输入(scanf)和输出(printf)函数和都需要包一个stdio.h这个头文件,要使用C++的输入输出,需要包含iostream这个头文件,这个头文件叫IO流。C++的头文件是不需要加.h,如果你用的编译器必须要加.h,说明这个编译器已经很老了(远古编译器),该去换了。
C++的输入和输出在std这个命名空间里,日常练习里我们可以去展开std这个命名空间,但是将来在公司里,或者是在一个很大项目里,就不要去展开std这个命名空间。
3.1.输出
输出需要用到的一个对象是cout,和流插入运算符<<,例如:
#include <iostream>
using namespace std;
int main()
{
cout << "hello world" << endl;
return 0;
}
endl我们可以理解为换行,cout是ostream这个类的实例,所以cout是一个对象。不懂也没有关系,后面我会详细的去写类和对象,只需要会用就行。
cout还会自动识别类型,例如:
#include <iostream>
using namespace std;
int main()
{
char ch = 'a';
int a = 10;
float b = 3.14;
cout << ch << endl;
cout << a << endl;
cout << b << endl;
cout << "hello world" << endl;
return 0;
}
3.2.输入
输出我们要用到的一个对象是cin,和流提取运算符>>,例如:
#include <iostream>
using namespace std;
int main()
{
int a = 0;
cin >> a;
cout << a << endl;
return 0;
}
cin是istream这个类的实例,所以cin是一个对象。
cin也支持自动识别类型,例如:
#include <iostream>
using namespace std;
int main()
{
char ch = 'a';
cin >> ch;
int a = 10;
cin >> a;
float b = 3.14;
cin >> b;
cout << ch << endl;
cout << a << endl;
cout << b << endl;
return 0;
}
3.3总结
1.输出用到的对象是cout和流插入运算符<<;
2.输入用到的对象是cin和流提取运算符>>;
3.cout和cin都支持自动识别类型;