概述
目录
- C++ 命名空间;流和文件I/O
- 命名空间
- 定义命名空间
- using指令
- 不连续的命名空间
- 嵌套的命名空间
- 流和文件I/O
- 流的概念
- C++的标准IO流
- C++的文件IO流
C++ 命名空间;流和文件I/O
命名空间
假设这样一种情况,当一个班上有两个名叫王明的学生时,为了明确区分他们,我们在使用名字之外,不得不使用一些额外的信息,比如他们的家庭住址,或者他们父母的名字,或者大家经常做的,起一个外号:大明,小明。
C++中也会出现这样的情况。
例如,如果我们写了一个名为 xyz() 的函数,在另一个可用的库中也存在一个相同的函数 xyz()。这样,编译器就无法判断我们所使用的是哪一个 xyz() 函数。
为了解决这个问题,就引入了命名空间的概念。
命名空间是通过作为附加信息来起到区分不同库中相同名称的函数、类、变量的作用的。
其实,使用了命名空间,就相当于定义了上下文,或者说,就是定义了一个范围,这个范围内,对含有相同名称的,只使用其中一种指定的函数、类、变量。
举一个最简单的例子,在计算机系统中,一个文件夹可以有多个文件夹,而且他们不能重名,但不同文件夹中的文件就可以重名了。
定义命名空间
使用关键字namespace来定义命名空间
namespace namespace_name {
// 代码声明
}
在调用带有命名空间的函数或者变量时,需要在前面加上命名空间的名称,如下:
name::code;//code指函数、类或变量
下面我们来看一个实例
#include <iostream>
using namespace std;
//第一个命名空间
namespace namespace_one
{
void func()
{
cout<<"这是第一个命名空间的函数"<<endl;
}
int x=1;
class myclass
{
public:
myclass()
{
cout<<"这是第一个命名空间的类"<<endl;
}
};
}
//第二个命名空间
namespace namespace_two
{
void func()
{
cout<<"这是第二个命名空间的函数"<<endl;
}
int x=2;
class myclass
{
public:
myclass()
{
cout<<"这是第二个命名空间的类"<<endl;
}
};
}
int main()
{
namespace_one::func();// 调用第一个命名空间中的函数
namespace_two::func();// 调用第二个命名空间中的函数
cout<<namespace_one::x<<endl;//输出第一个命名空间的变量
cout<<namespace_two::x<<endl;//输出第二个命名空间的变量
namespace_one::myclass zz;//实例化第一个命名空间的类的对象
namespace_two::myclass qq;//实例化第二个命名空间的类的对象
return 0;
}
运行结果如下,很容易就能理解,这里不再细讲
这是第一个命名空间的函数
这是第二个命名空间的函数
1
2
这是第一个命名空间的类
这是第二个命名空间的类
using指令
我们可以使用using namespace 指令,这样在使用命名空间时就可以不用在前面加上命名空间的名称。这个指令会告诉编译器,后续的代码将使用指定的命名空间中的名称。
其实我们在刚刚接触C++时用到的using namespace std;
就是使用了该指令,它告诉编译器,后续的函数,诸如cout
和cin
都是属于std命名空间,如果我们不用该代码,那么调用这两个函数时:
std::cout<<"whatever"<<std::endl;
下面是另一个简单的实例
#include <iostream>
using namespace std;
//第一个命名空间
namespace namespace_one
{
void func()
{
cout<<"这是第一个命名空间的函数"<<endl;
}
int x=1;
class myclass
{
public:
myclass()
{
cout<<"这是第一个命名空间的类"<<endl;
}
};
}
//第二个命名空间
namespace namespace_two
{
void func()
{
cout<<"这是第二个命名空间的函数"<<endl;
}
int x=2;
class myclass
{
public:
myclass()
{
cout<<"这是第二个命名空间的类"<<endl;
}
};
}
using namespace namespace_two;
int main()
{
func();// 调用第二个命名空间中的函数
cout<<x<<endl;//输出第二个命名空间的变量
myclass qq;
}
运行结果如下
这是第二个命名空间的函数
2
这是第二个命名空间的类
不连续的命名空间
事实上,命名空间可以定义在几个不同的部分中,即命名空间可以由几个单独定义的部分组成的,一个命名空间的各个组成部分可以分散在多个文件中。
所以,如果命名空间中的某个组成部分需要请求定义在另一个文件中的名称,则仍然需要声明该名称。下面的命名空间定义可以是定义一个新的命名空间,也可以是为已有的命名空间增加新的元素:
#include <iostream>
using namespace std;
//第一个命名空间
namespace namespace_one
{
void func()
{
cout<<"这是第一个命名空间的函数"<<endl;
}
int x=1;
class myclass
{
public:
myclass()
{
cout<<"这是第一个命名空间的类"<<endl;
}
};
}
//第二个命名空间
namespace namespace_two
{
void func()
{
cout<<"这是第二个命名空间的函数"<<endl;
}
int x=2;
class myclass
{
public:
myclass()
{
cout<<"这是第二个命名空间的类"<<endl;
}
};
}
namespace namespace_one//对第一个命名空间的补充
{
int addnum=123;
}
int main()
{
namespace_one::func();// 调用第一个命名空间中的函数
namespace_two::func();// 调用第二个命名空间中的函数
cout<<namespace_one::x<<endl;//输出第一个命名空间的变量
cout<<namespace_two::x<<endl;//输出第二个命名空间的变量
namespace_one::myclass zz;
namespace_two::myclass qq;
cout<<namespace_one::addnum<<endl;//输出补充的第一个命名空间的变量
return 0;
}
运行结果如下
这是第一个命名空间的函数
这是第二个命名空间的函数
1
2
这是第一个命名空间的类
这是第二个命名空间的类
123
嵌套的命名空间
我们可以在一个命名空间中定义另一个命名空间,即进行命名空间的嵌套。
我们在下面的代码中,通过namespace_one::namespace_two
来访问第二个命名空间的函数、变量以及类。
#include <iostream>
using namespace std;
//第一个命名空间
namespace namespace_one
{
void func()
{
cout<<"这是第一个命名空间的函数"<<endl;
}
int x=1;
class myclass
{
public:
myclass()
{
cout<<"这是第一个命名空间的类"<<endl;
}
};
//第二个命名空间
namespace namespace_two
{
void func()
{
cout<<"这是第二个命名空间的函数"<<endl;
}
int x=2;
class myclass
{
public:
myclass()
{
cout<<"这是第二个命名空间的类"<<endl;
}
};
}
}
namespace namespace_one//对第一个命名空间的补充
{
int addnum=123;
}
int main()
{
namespace_one::func();// 调用第一个命名空间中的函数
namespace_one::namespace_two::func();// 调用第二个命名空间中的函数
cout<<namespace_one::x<<endl;//输出第一个命名空间的变量
cout<<namespace_one::namespace_two::x<<endl;//输出第二个命名空间的变量
namespace_one::myclass zz;
namespace_one::namespace_two::myclass qq;
cout<<namespace_one::addnum<<endl;//输出补充的第一个命名空间的变量
return 0;
}
运行结果
这是第一个命名空间的函数
这是第二个命名空间的函数
1
2
这是第一个命名空间的类
这是第二个命名空间的类
123
流和文件I/O
流的概念
流是什么?流即是指流动,是物质从一处向另一处流动的过程,它是信息流动的一种抽象,负责在数据的生产者和数据的消费者之间建立联系,并管理数据的流动。
C++流是指信息从外部输入设备(如键盘)向计算机内部(如内存) 输入和从内存向外部输出设备(显示器)输出的过程。这种输入输出的过程被形象的比喻为流。
流的特性:有序且连续,具有方向性
为了实现这种流动,C++定义了I/O标准类库,这些每个类都称为流/流类,用以完成某方面的功能。
C++的标准IO流
C++标准库提供了4个全局流对象cin、cout、cerr、clog
- cin : 标准输入, 即数据通过键盘输入到程序中
- cout : 标准输出,即数据从内存流向控制台(显示器)
- cerr : 标准错误的输出
- clog : 日志的输出
cin和cout是我们熟知的,也是最常用的。
而cout,cerr和clog都是输出流。在早期, 他们是有所区别的, 在输出的优先级有所不同
显然,cerr 级别最高,程序一旦出错,报错一定是优先级最高的。
但今天这三种输出的差别越来越小,他们都可以输出数据,不过我们还是习惯使用cout而已。
如下
#include <iostream>
#include <string>
using namespace std;//别忘了这是指定使用std的命名空间
void makeout()
{
string str = "你看过倚天屠龙记吗?";
string str2 = "倚天屠龙记是金庸写的吗?";
string str3 = "不错,倚天屠龙记的主角是张无忌。";
cout << str << endl;
cerr << str2 << endl;
clog << str3<< endl;
}
int main()
{
makeout();
return 0;
}
结果如下,结果表明这三个函数都能输出数据
你看过倚天屠龙记吗?
倚天屠龙记是金庸写的吗?
不错,倚天屠龙记的主角是张无忌。
关于cin,cin为缓冲流,键盘输入数据后,数据会保存在缓冲区中,当要提取时,是从缓冲区中拿。如果一次输入过多,会按顺序从缓冲区一个一个取出数据,如果输入错了,必须在回车之前修改,如果回车键按下就无法挽回了。只有把输入缓冲区中的数据取完后,才要求输入新的数据。
如下
#include <iostream>
#include <string>
using namespace std;//别忘了这是指定使用std的命名空间
void makein()
{
string a,b,c;
cout<<"请输入一个你最喜欢的歌手"<<endl;
cin>>a;
cerr<<"请输入一首你最喜欢的歌曲"<<endl;
cin>>b;
clog<<"你想去那"<<endl;
cin>>c;
cout<<a<<endl;
cout<<b<<endl;
cout<<c<<endl;
}
int main()
{
makein();
return 0;
}
输入和输出如下
请输入一个你最喜欢的歌手
周杰伦 七里香 北京
请输入一首你最喜欢的歌曲
你想去那
周杰伦
七里香
北京
我们可以看到,我们接连输入了三个字符串,以空格进行分隔,但之后就不需要再次输入了,因为后面的cin函数会从缓冲区内取数据。但也正因为我们输入空格时计算机会将其认为分隔符,所以cin无法读取空格符作为输入,但我们可以使用getline(cin, str)
读取一行字符串
#include <iostream>
#include <string>
using namespace std;//别忘了这是指定使用std的命名空间
void makein()
{
string a,b,c;
cout<<"请输入一个你最喜欢的歌手"<<endl;
cin>>a;
cerr<<"请输入一首你最喜欢的歌曲"<<endl;
cin>>b;
clog<<"你想去那"<<endl;
cin>>c;
cout<<a<<endl;
cout<<b<<endl;
cout<<c<<endl;
}
int main()
{
string a;
cout<<"请输入一行字符串"<<endl;
getline(cin,a);//使用getline函数读取一行字符串,他能够读取空格
cout<<a<<endl;
return 0;
}
输入和输出如下
请输入一行字符串
1+2=3 3+4=7
1+2=3 3+4=7
如果想输入输出自己定义的对象,则可以使用用前面讲到的重载和友元。
如下:
#include <iostream>
#include <string>
using namespace std;//别忘了这是指定使用std的命名空间
class student
{
public:
student(string name,int x,int y)
{
this->name=name;
this->age=x;
this->height=y;
}
friend ostream& operator<<(ostream& cout, const student& s);
private:
int age,height;
string name;
};
ostream& operator<<(ostream& cout, const student& s)
{
cout<<"姓名:"<<s.name<<",年龄:"<<s.age<<",身高:"<<s.height<<endl;
}
int main()
{
student ming("ming",15,180);
cout<<ming<<endl;
}
结果如下:
姓名:ming,年龄:15,身高:180
C++的文件IO流
C++根据文件内容的格式,将其分为二进制文件和文本文件,对他们的读写方式也不一样。
二进制文件:字节流,读写效率高, 可读性差 (没有经过编码的二进制数据, 看起来都是乱码)
文本文件:字符流,读写效率低, 可读性好 (编码后的可读字符)
我们通过文件流对象操作文件:
- 定义一个文件流对象:
ifstream ifile(只输入用);
ofstream ofile(只输出用);
fstream iofile(既输入又输出用); - 使用文件流对象的成员函数打开一个磁盘文件,使得文件流对象和磁盘文件之间建立联系
- 使用提取和插入运算符对文件进行读写操作,或使用成员函数进行读写
- 关闭文件
下面是关于C++读写文本文件的基本知识:
文件打开模式:
- ios::in 读
- ios::out 写
- ios::app 行文件末尾
- ios::binary 二进制模式
- ios::nocreate 打开一个文件时,如果文件不存在,不创建文件。
- ios::noreplace 打开一个文件时,如果文件不存在,创建该文件。
- ios::trunc 打开一个文件,然后清空内容。
- ios::ate 打开一个文件时,将位置移动到文件尾。
文件指针位置在C++中的用法:它主要在seekg()函数中使用
- ios::beg 文件头
- ios::end 文件尾
- ios::cur 当前位置
常用的错误判断方法
- good()如果文件打开成功
- bad()打开文件时发生错误
- eof()到底文件尾
下面我们看几个读写文本文件的例子
#include <iostream>
#include <fstream>
using namespace std;
void TextFileWrite()
{
ofstream out;//定义一个只输出的ofstream对象
out.open("letter.txt",ios::trunc);//iso::trunc表示在打开文件前将文件清空,
//由于是写入,文件不存在则创建,创建时命名为letter.txt
char a = 'a';
for (int i = 1; i <= 26; i++)
{
if (i < 10)
{
out<<"0"<<i<<"t"<<a<<"n";
}
else
{
out<<i<<"t"<<a<<"n";
}
a++;
}
out.close();
//别忘了最后要close创建的对象
}
int main()
{
TextFileWrite();
return 0;
}
得到txt文件如下
01 a
02 b
03 c
04 d
05 e
06 f
07 g
08 h
09 i
10 j
11 k
12 l
13 m
14 n
15 o
16 p
17 q
18 r
19 s
20 t
21 u
22 v
23 w
24 x
25 y
26 z
加入一个读文件的函数
#include <iostream>
#include <fstream>
using namespace std;
void TextFileWrite()
{
ofstream out;//定义一个ofstream对象
out.open("letter.txt",ios::trunc);//iso::trunc表示在打开文件前将文件清空,由于是写入,文件不存在则创建
char a = 'a';
for (int i = 1; i <= 26; i++)
{
if (i < 10)
{
out<<"0"<<i<<"t"<<a<<"n";
}
else
{
out<<i<<"t"<<a<<"n";
}
a++;
}
out.close();
//别忘了最后要close创建的对象
}
void TextFileRead()
{
fstream in;//创建一个既可以输入也可以输出的fstream对象
char ch;
in.open("letter.txt",ios::in);
while (!in.eof())
{
in>>ch;
cout<<ch;
//一个字符一个字符的读取,并且输出在终端
cout<<'n';
}
in.close();//最终一定要close
}
int main()
{
TextFileWrite();
TextFileRead();
return 0;
}
写文件操作不变,但写完后一个字符一个字符地读取文件并输出
由于输出结果太长,这里不再列出
下面我们再看一个相对比较复杂的示例,它能够读取一个文本文件的数字,并且排序后写入到另一个文件
#include <iostream>
#include <fstream>
#include <cstdlib> //qsort在此头文件中声明
using namespace std;
const int MAX_NUM = 1000;
int a[MAX_NUM]; //存放文件中读入的整数
int MyCompare(const void * e1, const void * e2)
{ //用于qsort的比较函数
return *((int *)e1) - *((int *)e2);
}
int main()
{
int total = 0;//读入的整数个数
ifstream srcFile("in.txt",ios::in); //以文本模式打开in.txt备读
if(!srcFile) { //打开失败
cout << "无法打开文件" << endl;
return 0;
}
ofstream destFile("out.txt",ios::out); //以文本模式打开out.txt备写
if(!destFile) {
srcFile.close(); //程序结束前不能忘记关闭以前打开过的文件
cout << "无法打开文件" << endl;
return 0;
}
int x;
while(srcFile >> x) //可以像用cin那样用ifstream对象
a[total++] = x;//在数组中存储读到的整数
qsort(a,total,sizeof(int),MyCompare); //排序
for(int i = 0;i < total; ++i)
destFile << a[i] << " "; //可以像用cout那样用ofstream对象
destFile.close();
srcFile.close();
return 0;
}
看一个读写二进制文件的例子
#include <iostream>
#include <fstream>
using namespace std;
int BinaryFileWrite()
{
//创建fstream对象,可以读写nums.dat文件
fstream file("test2/num.dat", ios::out | ios::binary);
if (!file)
{
cout << "无法打开文件";
return 0;
}
//将该整数数组写入到二进制文件
int buffer[ ] = {12, 2, 3, 4, 5, 6, 7, 8};
int size = sizeof(buffer) / sizeof(buffer[0]);
file.write(reinterpret_cast<char *>(buffer), sizeof(buffer));
file.close ();
return 0;
}
int BinaryFileRead()
{
ifstream fin("test2/num.dat",ios::binary);
int nNum;//读取二进制文件中第一个int对象的值
fin.read((char*)&nNum,sizeof(int));
cout<<"int = "<<nNum<<endl;//输出读到的数字
fin.close();
return 0;
}
int main()
{
BinaryFileWrite();
BinaryFileRead();
return 0;
}
输出如下:
int = 12
最后
以上就是精明小虾米为你收集整理的C++程序设计——十二C++ 命名空间;流和文件I/O的全部内容,希望文章能够帮你解决C++程序设计——十二C++ 命名空间;流和文件I/O所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复