C++面向对象程序设计(七)——输入输出和模板

举报
陈沧夜 发表于 2022/04/29 22:17:08 2022/04/29
【摘要】 C++面向对象程序设计(七)——输入输出和模板 文章目录 C++面向对象程序设计(七)——输入输出和模板与输入输出流操作相关的类输出重定向输入重定向判断输入流结束istream类的成员函数 ...

C++面向对象程序设计(七)——输入输出和模板


程序设计与算法C++面向对象程序设计 github仓库

与输入输出流操作相关的类

ios
istream
ostream
ifstream
iostream
ofstream
fstream

isteam用于输入的流类,例如cin是该类的对象

ostream用于输出的流类,例如cout

ifstream是用于从文件读取数据的类

ofstream用于向文件写入的类

iostream既能输入又能输出的类

fstream既能从文件读取数据,又能向文件写入数据

输出重定向

#include<iostream>
using namespace std;
int main(){
int x,y;
cin >> x >> y;
freopen("test.txt","w",stdout);//输出重定向到text.txt文件
if( y ==0 )
    	cerr << "error." <<endl;
else
    	cout<<x/y;	//输出结果到test.txt
return 0;

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

输入重定向

#include<iostream>
using namespace std;
int main(){
double f;
int n;
freopen("t.txt","r",stdin);	//从t.txt读取数据
cin >> f >> n;
cout << f << "," << n << endl;
return 0;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

判断输入流结束

int x;
while(cin >> x)
{
    ......
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

istream类的成员函数

istream & getlinnen( char * buf, int bufSize);

从输入流读取bufSize-1个字符到缓冲区buf,或读到碰到\n为止

istream & getlinnen( char * buf, int bufSize,char delim);

从输入流读取bufSize-1个字符到缓冲区buf,或读到碰到delim字符为止

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

bool eof();判断输入流是否结束

int peek();返回下一个字符,但不从流中去掉

istream & putback( char c);将字符ch放回输入流

istream & ignore(int nCout = 1, int delim = EOF);从流中删掉最多nCout个字符,遇到EOF时结束

流操纵算子

需要#include<iomanip>

整数流的基数

流操纵算子。十进制dec,八进制oct,十六进制hex,setbase

浮点数的精度

precision是成员函数,调用方式为

cout.precision(5);

  
 
  • 1

setprecision是流操作算子,调用方式为

cout << setprecision(5);	//可以连续输出

  
 
  • 1

定点输出浮点数:

cout << setiosflags(ios::fixed) << setprecision(6) << endl;

  
 
  • 1

设置域宽

setw成员函数

cin >> setw(4)
cout << setw(4)

  
 
  • 1
  • 2

width流操纵算子

cin.width(5);
cout.width(5);

  
 
  • 1
  • 2

宽度不足用空格在左边补上

#include <iomanip>
using namespace std;
int main()
{
    int n =141;
    //十六进制,十进制,八进制先后输出
    cout << hex << n << " " << dec << n << " " << oct << n << endl;
    double x =1234567.89, y =12.34567;
     //保留5位有效数字
    cout << setprecision(5) << x << " " << y << " " << endl;
    //保留小数点后5位
    cout << fixed << setprecision(5) << x << " " << y << endl;
    //科学计数法输出,且保留小数点后5位
    cout << scientific << setprecision(5) << x << " " << y << endl;
    //非负数显示正号,输出宽度12字符,宽度不足使用'*'填补
    cout << showpos << fixed << setw(12) << setfill('*') << n << endl;
       //非负数不显示正号,输出宽度12字符,宽度不足使用'*'填补
    cout << noshowpos << fixed << setw(12) << setfill('*') << n << endl;
    //输出宽度12字符,宽度不足左边用填充字符填充
    cout << setw(12) << right << n << endl;
    //宽度不足时,负号和数值分列左右,中间用填充字符填充
    cout << setw(12)<< internal << n<< endl;
    
    return 0;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

用户自定义流操作算子

ostream & tab(ostream & output){
    return output << '\t';
}

cout << "aa" << tab << "bb" << endl;

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

文件读写

创建文件

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

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
//也可以先创建ofstream对象,再用open打开
ofstream fout;
fout.open("test.out",ios::out|ios::binary);

  
 
  • 1
  • 2
  • 3
//判断打开是否成功
if(!fout){
    cout << "File open error!" <<endl;
}

  
 
  • 1
  • 2
  • 3
  • 4

文件名可以给出绝对路径,也可以给相对路径。默认当前文件夹找文件

文件的读写指针

对于输入文件,有一个读指针

对于输出文件,有一个写指针

对于输入输出文件,有一个读写指针

标识文件操作的当前位置,该指针在哪里,读写操作就在哪里进行

ofstream fout("a1.out",ios::app);	//以添加方式打开
long location = fout.tellp();	//取得写指针的位置
location = 10;	
fout.seekp(location);	//将写指针移动到第10个字节处
fout.seekp(location,ios::beg);	//从头数location
fout.seekp(location,ios::cur); //从当前位置数location
fout.seekp(location,ios::end);//从尾部数location

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
ifstream fin("a1.in",ios::ate);	//打开文件,定位文件指针到文件尾
long location = fin.tellg();	//取得指针的位置
location = 10L;	
fin.seekg(location);	//将读指针移动到第10个字节处
fin.seekg(location,ios::beg);	//从头数location
fin.seekg(location,ios::cur); //从当前位置数location
fin.seekg(location,ios::end);//从尾部数location

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

location可以为负值

字符文件读写

#include<iostream>
#include<fstream>
#include<vector>
#include<alogrithm>

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)
        v.push_back(x);
sort(v.begin(),v.end());
for(int i = 0 ;i < v.size();i++)
        destFile << v[i] << " ";
destFile.close();
srcFile.close();
return 0;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

二进制文件读写

二进制读文件

istream & read (char * s, long n);
/*将文件读指针指向的地方的n个字节的内容,读入到内存地址s,然后将文件读指针向后移动n字节*/

  
 
  • 1
  • 2

二进制写文件

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

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
#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 ));
    fout.close();
    ifstream fin("some.dat",ios::in|ios::binary);
    int y;
    fin.read((char * ) &y,sizeof(int));
    fin.close();
    cout << y << endl;
    return 0;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
#include<iostream>
#include<fstream>

using namespace std;

struct Student{
    char name[20];
    int score;
};
//输入
int main()
{
    Student s;
    ofstream OutFile("c:\\tmp\\students.dat",ios::out|ios::binary);
    while(cin >> s.name >> s.score)
        OutFile.write((char *) & s,sizeof(s));
    OutFile.close();
    return 0;
}

//读出
int main()
{
	Student s;
    ifstream inFile("c:\\tmp\\students.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();
    return 0;
}
//修改

{
	Student s;
    fstream iofile("c:\\tmp\\students.dat",ios::in|ios::out|ios::binary);
    if(!ioFile){
        cout << "error" << endl;
        return 0;
    }
	iofile.seekp(2*sizeof(s),ios::beg);
    iofile.write("Mike",strlen("Mike")+1);
    iofile.seekg(0,ios::beg);
    while(iofile.read((char *)&s,sizeof(s)))
        cout << s.name <<" "<< s.score <<endl;
    iofile.close();
    return 0;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

函数模板

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

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
template <class T>
void Swap(T & x, T & y)
{
T tmp = x;
x = y;
y =tmp;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

实例:

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(duble &,double & )函数
    return 0; 

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

函数模板中可以有不止一个参数

template <class T1,class T2>
T2 print(T1 arg1,T2 arg2)
{
    cout << arg1 << " " << arg2 << endl;
    return arg2;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

函数模板可以重载,只要形参表或类型参数表不同即可

多个函数和函数模板名字相同的情况下,编译器处理顺序

​ 1.先找参数完全匹配的普通函数

​ 2.再找参数完全匹配的模板函数

​ 3.实参经过自动类型转换后能够匹配的普通函数

匹配模板函数时,不进行类型自动转换

//函数模板实例Map
#include<iostream>
using namespace std;
template<class T,class Pred>
void Map(T s, T e, T x,Pred op)
{
    for(; s!=e;++s,++x){
        *x = op(*s);
    }
}
int Cube(int x){
    return x*x*x;
}
double Square(double x){
    return x*x;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

类模板

//类模板定义
template<typename 类型参数1, typename 类型参数2,……>
class 类模板名
{
			成员函数和成员变量
};
//类模板成员函数写法:
template<class 类型参数1, class 类型参数2,……>
返回值类型 类模板名<类型参数名列表>::成员函数名 (参数表)
{
			函数体
};
//用类模板定义对象的写法:
类模板名<真实类型参数表>对象名(构造函数实参表);

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
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
{
    return key<p.key;
}

int main(){
    Pair<string,int>student("Tom",19);
    cout << student.key << " " <<student.value;
    return 0;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

同一个类模板的两个模板类是不兼容的

## 类模板和派生

  1. 类模板从类模板派生
  2. 类模板从模板类派生
  3. 类模板从普通类派生
  4. 普通类从模板类派生

类模板和友元

函数,类,类的成员函数作为类模板的友元

函数模板作为类模板的友元

函数模板作为类的友元

类模板作为类模板的友元

类模板与static成员

#include<iostream>

using namespace std;
template <class T>
class A
{
    private:
    	static int count;
    public:
    A(){count++;}
    ~A(){count--;}
    A(A&){count ++ ;}
    static void PrintCount(){cout << count <<endl;}
};
template<> int A<int> :: count = 0;
template<>int A<double>::count = 0;
int main(){
    A<int> ia;
    A<double> da;
    ia.PrintCount();
    da.PrintCount();
    return 0;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

文章来源: blog.csdn.net,作者:沧夜2021,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/CANGYE0504/article/details/105390214

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。