《C++面向对象程序设计》课程笔记 lessen7

1. 输入输出流相关的类

  •  istream 是用于输入的流类, cin 就是该类的对象。 
  • ostream 是用于输出的流类, cout 就是该类的对象。 
  • ifstream 是用于从文件读取数据的类。
  • ofstream 是用于向文件写入数据的类。
  • iostream 是既能用于输入,又能用于输出的类。
  • fstream 是既能从文件读取数据,又能向文件写入数据的类。 
  • 输入流对象:cin 与标准输入设备相连,对应于标准输入流。用于从键盘读取数据,也可以被重定向为从文件中读取数据。
  • 输出流对象:cout 与标准输出设备相连,对应于标准输出流。用于向屏幕输出数据,也可以被重定向为向文件写入数据。

                             cerr 与标准错误输出设备相连,对应于标准错误输出流,用于向屏幕输出出错信息。

                             clog 与标准错误输出设备相连 ,对应于标准错误输出流,用于向屏幕输出出错信息。               

缺省情况下:(三者一样)

cerr << "Hello World!" << endl;
clog << "Hello World!" << endl;
cout << "Hello World!" << endl;

 输出流重定向:

#include <iostream>
using namespace std;

int main()
{
	int x,y;
	cin >> x >> y;
	freopen("test.txt","w",stdout); //将标准输出重定向到 test.txt 文件
	if( y==0 ) //除数为0则在屏幕上输出错误信息
		cerr << "errer" <<endl;
	else
		cout << x/y;  //输出结果到 test.txt

	system("pause");
	return 0;
}

输入流重定向:

int main()
{
	double f;
	int n;
	freopen("t.txt","r",stdin);  //cin 被改为从 t.txt 中读取数据
	cin >> f >>n;
	cout << f << "," << n << endl;

	system("pause");
	return 0;
}

istream 类的成员函数:

istream & getline(char * buf, int bufsize);

 该函数从输入流中读取 bufsize-1 个字符到缓冲区 buf ,或读到 ‘\n’ 为止(哪个先到算哪个)。

istream & getline(char * buf, int bufsize, char delim);

该函数从输入流中读取 bufsize-1 个字符到缓冲区 buf ,或读到 delim 字符为止(哪个先到算哪个)。

两个函数都会自动在 buf 中读入数据的结尾添加 '\0' 。'\n' 或 delim 都不会被读入 buf ,但会被从输入流中取走。

可以用 if( !cin.getline(...) ) 判断输入是否结束。

#include <iostream>
using namespace std;

int main()
{
	int x;
	char buf[100];
	cin >> x;
	cin.getline(buf,90);
	cout << buf <<endl;

	system("pause");
	return 0;
}

2. 流操纵算子 

  • 整数流的基数:流操纵算子 dec(十进制), oct(八进制), hex(十六进制), setbase(任意进制)
  • 浮点数的精度(precision, setprecision)
  • 设置域宽(setw, width)
  • 用户自定义的流操纵算子 

使用流操纵算子需要 #include <iomanip> 

1 整数流的基数

#include <iostream>
#include <iomanip>
using namespace std;

int main()
{
	int n = 10;
	cout << n << endl;
	cout << hex << n <<endl; //十六进制
	cout << dec << n <<endl; //十进制
	cout << oct << n <<endl; //八进制

	system("pause");
	return 0;
}

2 控制浮点数精度的流操纵算子

  • precision 是成员函数,其调用方式为: 
cout.precision(5);
  • setprecision 是流操作算子,其调用方式为:
cout << setprecision(5); //可以连续输出

它们的功能相同。指定输出浮点数的有效位数(非定点方式输出时)。指定输出浮点数小数点后的有效位数(定点方式输出时)。定点方式:小数点必须出现在个位数后面。

#include <iostream>
#include <iomanip>
using namespace std;

int main()
{
	double x = 1234567.89,y = 12.34567;
	int n = 1234567;
	int m = 12;
	cout << setprecision(6) << x <<endl << y << endl << n << endl << m; 
	//浮点数输出最多6位有效数字(缺省情况下为非定点方式输出)
	system("pause");
	return 0;
}

//输出: 1.23457e+006
        12.3457
        1234567  (整数不受精度影响)
        12

设置和取消以小数点固定位置方式(定点方式)输出的代码:

cout << setiosflags(ios::fixed);
cout << resetiosflags(ios::fixed);
cout << setiosflags(ios::fixed) << setprecision(6) << x <<endl << y << endl << n << endl << m; 

//输出 :1234567.890000
        12.345670
        1234567
        12

3 设置域宽的流操纵算子

setw 是流操作算子,width 是成员函数。

cin >> setw(4); 
cin.width(5);
cout << setw(4);
cout.width(5);

 宽度设置有效性是一次性的,在每次读入和输出之前都要设置宽度。

#include <iostream>
#include <iomanip>
using namespace std;

int main()
{
	int w = 4;
	char string[10];
	cin.width(5);        //读入域宽时包含 '\0'
	while(cin>>string)
	{
		cout.width(w++);    //输出时域宽不包含 '\0'。字符不够时在前面补空格
		cout<<string<<endl;
		cin.width(5);
	}

	system("pause");
	return 0;
}

//输出:1234567890
       1234
        5678     //字符不够时在前面补空格
           90

3. 文件读写

1 创建文件

#include <fstream>  //包含头文件

ofstream outFile("clients.dat",ios::out|ios::binary);
  • "clients.dat"         要创建的文件的名字
  •  ios::out               文件打开方式
  •       ios::out          输出到文件,删除原因内容
  •       ios::app         输出到文件,保留原有内容,总是在尾部添加
  • ios::binary           以二进制文件格式打开文件 

也可以先创建  ofstream 对象,再用 open 函数打开:

ofstream fout;
fout.open("test.out",ios::out|ios::binary);

判断打开是否成功:

if (!fout)
{
	cout << "File open error!" << endl;
}

文件名可以给出绝对路径,也可以给相对路径。没有交代路径信息,就是在当前文件夹下找文件。

2 字符文件读写 

写一个程序,将文件 in.txt 里面的整数排序后,输出到 out.txt

例如:若  in.txt 的内容为:1 234 9 45 6 879

          则执行本程序后。生成的 out.txt 的内容为:1 6 9 45 234 879

#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
using namespace std;

int main()
{
	vector<int> v;
	ifstream srcFile("in.txt",ios::in);
	ofstream destFile("out.txt",ios::out);
	int x;
	while( srcFile >> x )          //ifstream 是 istream 的派生类,istream 有的操作 ifstream 也有
		v.push_back(x);
	sort(v.begin(),v.end());
	for (int i=0;i<v.size();i++)
	{
		destFile << v[i] << " ";  //ofstream 是 ostream 的派生类,ostream 有的操作 ofstream 也有
	}
	destFile.close();
	srcFile.close();

	system("pause");
	return 0;
}

3 二进制文件读写

  • 二进制读文件 

 ifstream 和 fstream 的成员函数:

istream & read(char *s, long n);

将文件读指针指向的地方的 n 个字节内容,读入到内存地址 s ,然后将文件读指针向后移动 n 字节(以 ios::in 方式打开文件时,一开始文件读指针指向文件开头)。

  • 二进制写文件 
istream & write(const char* s, long n);

将内存地址 s 处的 n 个字节内容,写入到文件中写指针指向的位置,然后将文件写指针向后移动 n 字节(以 ios::out 方式打开文件时,文件写指针一开始指向文件开头,以 ios::app 方式打开文件时,文件写指针一开始指向文件尾部)。

在文件中写入和读取一个整数例程:

#include <iostream>
#include <fstream>
using namespace std;
int main()
{
	ofstream fout("some.dat",ios::out|ios::binary);
	int x = 120;
	fout.write((const char *)(&x),sizeof(int)); //x 的内存地址为 &x,是 int* 类型,而参数类型需为 const char* 类型。
	fout.close();
	ifstream fin("some.dat",ios::in|ios::binary);
	int y;
	fin.read((char *)(&y),sizeof(int));
	fin.close();
	cout << y <<endl;

	system("pause");
	return 0;
}

从键盘输入几个学生的姓名和成绩,并以二进制文件形式保存。

#include <iostream>
#include <fstream>
using namespace std;
struct Student
{
	char name[20];
	int score;
};

int main()
{
	Student s;
	ofstream OutFile("student.dat",ios::out|ios::binary);
	while(cin >> s.name >> s.score)
		OutFile.write((char *)(&s),sizeof(s)); //每个 s 占24字节
	OutFile.close();

	system("pause");
	return 0;
}

将 student.dat 文件内容读出并显示:

struct Student
{
	char name[20];
	int score;
};

int main()
{
	Student s;
	ifstream inFile("student.dat",ios::in|ios::binary);
	if (!inFile)
	{
		cout << "error" <<endl;
		return 0;
	}
	while(inFile.read((char *)(&s),sizeof(s)))
	{
		int readedBytes = inFile.gcount(); //看刚才读了多少字节
		cout << s.name << " " << s.score << endl;
	}
	inFile.close();	 

	system("pause");
	return 0;
}

4. 函数模板

1 函数模板的格式 

template <class 类型参数1,class 类型参数2,...>
返回值类型 模板名(形参表)
{
	函数体
}

template <class T>
void Swap(T & x,T & y)
{
	T tmp = x;
	x = y;
	y = tmp;
}

int main()
{
	int n = 1,m = 2;
	Swap(n , m); //编译器自动生成 void Swap(int &,int &)函数
	double f = 1.2,g = 2.3;
	Swap(f,g);   //编译器自动生成 void Swap(double &,double &)函数
//  Swap(n,f);   //error.匹配模板函数时,不进行类型自动转换

	system("pause");
	return 0;
}
  •  函数模板中可以有不止一个类型参数。
  • 函数模板可以重载,只要它们的形参表或类型参数表不同即可。
  • 匹配模板函数时,不进行类型自动转换.

函数模板实例:Map 

//函数模板实例:Map
template<class T,class Pred>
void Map(T s,T e,T x,Pred op) //s 起点位置,e 终点位置,op 变换,然后复制到起点为 x 的地方
{
	for(; s != e; ++s,++x)
	{
		*x = op(*s);
	}
}

int Cube(int x)
{
	return x * x * x;
}

double Square(double x)
{
	return x * x;
}

int a[5] = {1,2,3,4,5},b[5];
double d[5] = {1.1,2.1,3.1,4.1,5.1}, c[5];
int main()
{
	Map(a,a+5,b,Square); //void Map(int * s,int * e,int * x,double (*op)(double))  //第四个参数是函数指针类型(返回值double,参数double)
	for(int i=0;i<5;++i)
		cout << b[i] <<",";
	cout << endl;

	Map(a,a+5,b,Cube);
	for(int i=0;i<5;i++)
		cout << b[i] << ",";
	cout << endl;

	Map(d,d+5,c,Square);
	for(int i=0;i<5;i++)
		cout << c[i] << ",";
	cout << endl;
    
	system("pause");
	return 0;
}

 5. 类模板

template <class 类型参数1,class 类型参数2,...>
(也可以)template <typename 类型参数1,typename 类型参数2,...>
//类型参数表
class 类模板名
{
	成员函数和成员变量
};

类模板里成员函数的写法: 

template <class 类型参数1,class 类型参数2,...> //类型参数表
返回值类型 类模板名<类型参数名列表>::成员函数名 (参数表)
{
	......
}

用类模板定义对象的写法:

类模板名 <真实类型参数表> 对象名(构造函数实参表);

 类模板实例:Pair类模板

//类模板实例:Pair类模板
template <class T1,class T2>
class Pair
{
public:
	T1 key; //关键字
	T2 value;  //值
	Pair(T1 k,T2 v):key(k),value(v) { };
	bool operator < (const Pair<T1,T2> & p) const;
};

template<class T1,class T2>
bool Pair<T1,T2>::operator<(const Pair<T1,T2> & p) const
{//Pair 的成员函数 operator <
	return key < p.key;
}

int main()
{
	Pair<string,int> student("Tom",19);
	//实例化出一个类 Pair<string,int>
	cout << student.key << " " << student.value;

	system("pause");
	return 0;

}
  • 同一个类模板的两个模板类是不兼容的。完全不相关。

猜你喜欢

转载自blog.csdn.net/sinat_35483329/article/details/85089006