c++学习 文件操作,模板

文件操作

cpp 复制代码
#include<iostream>
#include<string>
#include<fstream>
using namespace std;
//文本操作
//程序运行时产生的数据都属于临时数据,程序一旦运行结束都会被释放
//通过文件可以数据持久化
//c++中对文件操作包含头文件<fstream>
//文件类型分为两种:
//1.文本文件 -文件以文本的ASCLL码形式存储在计算机中
//2.二进制文件 - 文件以文本的二进制形式存储在计算机中,用户一般不能直接读懂它们
//操作文件的三大类
//1.ofstream:写操作
//2.ifstream:读操作
//3.fstream: 读写操作 
//写文件
//1.包含头文件
//#include<fstream> 
//2.创建流对象
//ofstream ofs;
//3.打开文件
//ofs.open("文件路径",打开方式); 
//文件打开方式:
//ios::in 读文件方式打开
//ios::out 写文件方式打开
//ios::ate 初始位置:文件尾
//ios::app 追加文件方式打开
//ios::trunc 如果文件存在先删除,再创建
//ios::binary 二进制方式 
//文件打开方式可以配合使用,利用|操作符 
//4.写数据
//ofs<<"写入的数据"; 
//5.关闭文件 
//ofs.close();
void test(){
	//1.包含头文件
	//2.创建流对象 
	ofstream ofs;
	//3.指定打开方式
	ofs.open("text.txt",ios::out);
	//4.写内容
	ofs<<"姓名:张三"<<endl;
	ofs<<"性别:男"<<endl;
	ofs<<"年龄:25"<<endl; 
	//5.关闭文件 
	ofs.close();
} 
//读文件
//1.包含头文件
//#include<fstream>
//2.创建流对象
//ifstream ifs;
//3.打开文件并判断文件是否打开
//ifs.open("文件路径",打开方式);
//4.读数据
//四种方式读取
//5.关闭文件
//ifs.close() 
void test1(){
	//1、包含头文件
	//2、创建流对象
	ifstream ifs; 
	//3、打开文件并判断文件是否打开
	ifs.open("text.txt",ios::in);
	if(!ifs.is_open()){
		cout<<"文件打开失败"<<endl;
		return;
	}
	//4、读数据
	//第一种 
	char buf[1023] = {0};
	while(ifs >> buf) {
		cout<<buf<<endl;
	}
//	//第二种
//	char buf[1024] = {0};
//	while(ifs.getline(buf,sizeof(buf))) {
//		cout<<buf<<endl;
//	}
//	//第三种
//	string buf;
//	while(getline(ifs,buf)){
//		cout<<buf<<endl;
//	} 
	//第四种
//	char c;
//	while((c = ifs.get()) != EOF){ //EOF end of file 
//		cout<<c;	
//	} 
	//5、关闭文件 
	ifs.close();
}
//二进制文件
//以二进制的方式对文件进行读写操作
//打开方式要指定为ios::binary 
//二进制文件写文件
//二进制方式写文件主要利用流对象调用成员函数write
//函数原型:ostream&write(const char *buffer,int len);
//参数解释:字符指针buffer指向内存中一段存储空间。len是读写的字节数 
class Person{
	public:
		char m_Name[64];
		int m_Age;
}; 
void test2(){
	//1.包含头文件
	//2.创建流对象
	ofstream ofs; 
	//3.打开文件
	ofs.open("person.txt",ios::out|ios::binary);
	//创建流对象和打开文件一起 
//	ofstream ofs("person.txt",ios::out|ios::binary);
	//4.写文件
	Person p = {"张三",18} ;
	ofs.write((const char *)&p, sizeof(p));
	//5.关闭文件 
	ofs.close();
	 
}
//二进制文件读文件
//函数原型:istream&read(char *buffer,int len); 
class Person1{
public:	
	char m_Name[64];
	int m_Age;
}; 
void test3(){
	//1.包含头文件
	//2.创建流对象
	ifstream ifs; 
	//3.打开文件 判断文件是否打开成功 
	ifs.open("person.txt",ios::in|ios::binary);
	if(! ifs.is_open()){
		cout<<"文件打开失败"<<endl; 
		return;
	}
	//创建流对象和打开文件一起 
//	ifstream ofs("person.txt",ios::out|ios::binary);
	//4.读文件
	Person1 p;
	ifs.read((char *)&p, sizeof(Person1));
	cout<<"姓名:"<<p.m_Name<<" 年龄:"<<p.m_Age<<endl; 
	//5.关闭文件 
	ifs.close();
}
int main(){
	//文本文件写 
	test();
	//文本文件读 
	test1();
	//二进制文件写 
	test2();
	//二进制文件读
	test3(); 
} 

模板:

cpp 复制代码
#include<iostream>
#include<string>
using namespace std;

//1.2函数模板语句
//c++另一种编程思想称为泛型编程,主要利用的技术就是模板 
//c++提供两种模板机制:函数模板和类模板
//1.2.1函数模板作用:
//建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表
//语法: template<typename T> 
//       函数声明或定义
//template --- 声明创建模板
//typename --- 表明其后面的符号是一种数据类型,可以用class代替
//T --- 通用的数据类型,名称可以替换,通常为大写字母 

//函数模板
template<typename T> 

void mySwap(T &a,T &b)
{
	T temp = a;
	a = b;
	b = temp;
} 
两个整型交换函数
//void swapInt(int &a,int &b)
//{
//	int temp = a;
//	a = b;
//	b = temp;
//} 
交换两个浮点型函数
//void swapDouble(double &a,double &b)
//{
//	double temp = a;
//	a = b;
//	b = temp;
// } 
 
 void test01()
 {
 	cout<<"************test01**********"<<endl
	 	<<"***********函数模板*********"<<endl; 
 	int a = 10;
 	int b = 20;
//	swapInt(a,b);
//	cout<<"a = "<<a<<" b = "<<b<<endl; 
//	
//	double c = 1.1;
//	double d = 2.2;
//	swapDouble(c,d);
//	cout<<"c = "<<c<<" d = "<<d<<endl;
    //函数模板两种使用方法 
    //1、自动类型推导
	mySwap(a,b);
	cout<<"a = "<<a<<" b = "<<b<<endl;
	//2、显示指定类型
	mySwap<int>(a,b); 
	cout<<"a = "<<a<<" b = "<<b<<endl;
 }
 //1.2.2 函数模板注意事项
 //注意事项:
 //1、自动类型推导,必须导出一致的数据类型T,才可以使用
 
 //2、模板必须要确定出T的数据类型,才可以使用
 //template <class T>
 //void func() 
// {
// 	cout<<"func 调用"<<endl;
// }
//调用func()是错误的,必须明确func的数据类型 
  
  
//1.2.3 函数模板案例
//案例描述:
//利用函数模板封装一个排序的函数。可以对不同类型数组进行排序
//排序规则从大到小,排序算法为选择排序
//分别利用char数组和int数组进行测试 

//排序算法
template <typename T>
void mySort(T arr[], int len)
{
	for(int i = 0;i < len;i++)
	{
		int max = i;
		for(int j = i+1; j<len; j++)
		{
			if(arr[max]<arr[j]) // 此处是max 不是 i,需要实时更新max的值 
			{
				max = j;
			}
		}
		if(max!=i)
		{
			mySwap(arr[i],arr[max]);
		}
	}
 } 
 
// 6,432,432,32,32
// i = 0; max = 0 j = 1 32
// i = 1; max = 1 j = 2 432
// i = 2; max = 2 j = 3 432
// i = 3; max = 3 j = 4  max = 4  2
// i = 4; max = 4 j = 5  max = 4  1

 //打印 
 template <typename T>
 void show(T arr[],int len)
 {
 	for(int i = 0; i < len;i++)
 	{
 		cout<<arr[i]<<" ";	
	}
	cout<<endl; 
 }
 
void test02()
{
	cout<<"************test02**********"<<endl
	 	<<"********函数模板测试排序*******"<<endl;
	char charArr[] = "fdacbeg";
	int intArr[] = {6,432,432,32,32};

	int len = sizeof(charArr)/sizeof(charArr[0]);
	int size = sizeof(intArr)/sizeof(intArr[0]);
	
	show(charArr,len);
	mySort(charArr,len); 
	show(charArr,len); 
	
	show(intArr,size);
	mySort(intArr,size); 
	show(intArr,size); 
}
//1.2.4 普通函数与函数模板的区别
//普通函数与函数模板区别
//普通函数调用时可以发生自动类型转换(隐式类型转换)
//函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
//int myAadd(int a, int b)
//{
//	return a + b;
// } 
// myAadd(10,"c");//不会报错,隐式类型转换,转为ACI码相加 
//template<typename T>
//T  myAdd02(T a, T b)
//{
//	return a + b;
//}
// myAadd02(10,"c");//会报错,隐式类型不能转换
//1.2.5普通函数与函数模板的调用规则
//调用规则如下:
//1.如果函数模板和普通函数都可以实现,优先调用普通函数
//2.可通过空模板参数列表来强调调用函数模板
//3.函数模板也可以发生重载
//4.如果函数模板可以产生更好的匹配,优先调用函数模板 

//void myPrint(int a,int b)
//{
//	cout<<"调用的模板"<<endl; 
// }
// 
//template<class T>
//void myPrint(T a,T b)
//{
//	cout<<"调用的模板"<<endl; 
//} 
//template<class T>
//void myPrint(T a,T b , T c)
//{
//	cout<<"调用的重载的模板"<<endl; 
//
//void test01()
//{
//	int a = 10;
//	int b = 20;
//	
//	myPrint(a,b);//优先调用普通函数 
//通过空模板参数列表,强制调用函数模板
// myprint<>(a,b); 
// myprint(a,b,c); 函数模板也可以发生重载 
   //如果函数模板产生更好的匹配,优先调用函数模板 
//   char c1 = "a";
//   char c2 = "b";
//   myprint(c1,c2); // 调用的是模板 
//}
//1.2.6模板的局限性
//模板的通用并不是万能的
//例如  
//如果传入的 a 和 b 是一个数组,就无法实现了 
//template<class T>
//void f(T a,T b)
//{
//	a = b;	
//}  
//再例如:
//template<class T>
//void f(T a, T b)
//{
//	if(a > b){
//		
//	}
//}                        
//在上述代码中,如果T的数据类型传入的是像Person这样的自定义数据类型,也无法正常运行
class person{
public:
	person(string name,int age){
		this->myname = name;
		this->myage = age;
	}
	string myname;
	int myage;
};
template<class T>
bool equals (T &a,T &b)
{
	if(a == b)
	{
		return true ;
	}
	else
	{
		return false;
	}
}
//利用具体化person的版本实现代码,具体化优先调用
template<>bool equals(person &p1,person &p2){
	if(p1.myname == p2.myname && p1.myage == p2.myage){
		return true;
	}
	else{
		return false;
	}
} 

void test03()
{
	cout<<"************test03**********"<<endl
	 	<<"********模板的局限性*******"<<endl;
	int a = 10;
	int b = 10;
	int ret = equals (a,b);
	if(ret){
		cout<<"a等于b"<<endl; 
	}
	else{
		cout<<"a不等于b"<<endl;
	}
}

void test04()
{
	cout<<"************test04**********"<<endl
	 	<<"********模板的局限性*******"<<endl;
	person p1("tom",10);
	person p2("tom",10);
	
	bool ret = equals(p1,p2);
	
	if(ret){
		cout<<"p1 等于 p2"<<endl; 
	}
	else
	{
		cout<<"p1 不等于 p2"<<endl; 
	} 
}
//1.3类模板
//1.3.1类模板语法 
//类模板作用:
//建立一个通用类,类中成员 数据类型可以不具体制定,用一个虚拟的类型来代表 
//语法:
template<class NameType,class AgeType>
//类 
class Person1{
	public:
	Person1(NameType name,AgeType age)
	{
		this->m_Name = name;
		this->m_age = age;
	}
	void showPerson()
	{
		cout<<"name:"<<this->m_Name<<" age: "<<this->m_age<<endl;
	 } 
	NameType m_Name;
	AgeType  m_age; 
}; 

void test05()
{
	cout<<"************test05**********"<<endl
	 	<<"************类模板************"<<endl;
	Person1<string, int>p1("孙悟空",999);
	p1.showPerson();
 } 
//1.3.2类模板与函数模板区别
//类模板与函数模板主要有两点
//1.类模板没有自动类型推导的使用方式
//Person1 p1("孙悟空",999);//错误无法自动类型推导 
//2.类模板在模板参数列表中可以有默认参数 
//template<class NameType,class AgeType = int>
//Person1<string>p1("孙悟空",999); // 不会报错,有默认参数 
//1.3.3类模板中成员函数创建时机
//类模板中成员函数和普通类中成员函数创建时机是有区别的:
//类模板中的成员函数在调用时才创建 
class Person2
{
	public:
		void showPerson2()
		{
			cout<<"person2 show"<<endl; 
		}
 }; 

class Person3
{
	public:
		void showPerson3()
		{
			cout<<"person3 show"<<endl;
		}
};

template<class T>
class Myclass
{
	public:
		T obj;
		void fun1()
		{
			obj.showPerson2();
		}
		void fun2()
		{
			obj.showPerson3();
		}
};
void test06()
{
	cout<<"************test06**********"<<endl
	 	<<"********类模板的创建时机*******"<<endl;
	Myclass<Person2> m;
	m.fun1();
	//m.fun2(); fun2 报错 ,Person2类只能使用fun1函数 
	
}
//1.3.4类模板对象做函数参数
//三种传入方式:
//1.指定传入的类型 --- 直接显示对象的数据类型
template<class T1,class T2>
class Person4
{
	public:
	Person4(T1 name, T2 age)
		{
			this->m_name = name;
			this->m_age = age;
		 } 
	void showPerson()
	{
		cout<<"姓名:"<<m_name<<" 年龄:"<<m_age<<endl; 
	}
	T1 m_name;
	T2 m_age;
}; 

void printPerson4_0(Person4<string, int>&p) //指定传入的类型
{
	p.showPerson();
}
//2.参数模板化  ---将对象中的参数变为模板进行传递
template<class T1,class T2>
void printPerson4_1(Person4<T1, T2>&p)
{
	p.showPerson();
//	cout<<"T1的类型为:"<<typeid(T1).name()<<endl; // 查看T1的数据类型 
}
//3.整个类模板化 ---将这个对象类型模板化进行传递 
template<class T> 
void printPerson4_2(T &p)
{
	p.showPerson();
//	cout<<"T1的类型为:"<<typeid(T1).name()<<endl; // 查看T1的数据类型 
}
void test07()
{
	cout<<"************test07**********"<<endl
	 	<<"********类模板对象做函数参数*******"<<endl;
	Person4<string, int>p("天蓬元帅",1999);
	printPerson4_0(p);
	printPerson4_1(p);
	printPerson4_2(p);
}
//1.3.5类模板与继承
//当子类继承的父类是一个类模板时,子类在声明的时候,要指出父类中T的类型
//如果不指定,编译器无法给子类分配内存
//如果想灵活指定出父类中T的类型,子类也需变为类模板
//
//template<class T>
//class Base
//{
//	T m;
//}; 
class Son:public Base //错误,必须要知道父类中的T类型,才能继承给子类 
//
//class Son:public Base<int>
//{
//	
//};
// 
//template<class T1,class T2>
//class Son1:public Base<T2>
//{
//	T1 obj;
//};
//Son1<int,char> s; // 调用 
//1.3.6 类模板成员函数类外实现
template<class T1,class T2>
class Person5
{
	public:
	Person5(T1 name, T2 age);
//		{
//			this->m_name = name;
//			this->m_age = age;
//		 } 
	void showPerson();
//	{
//		cout<<"姓名:"<<m_name<<" 年龄:"<<m_age<<endl; 
//	}
	T1 m_name;
	T2 m_age;
};

//构造函数内外实现
template<class T1,class T2>
Person5<T1,T2>::Person5(T1 name, T2 age)
{
	this->m_name = name;
	this->m_age = age;
}  
//成员函数类外实现
template<class T1,class T2>
void Person5<T1,T2>::showPerson()
{
	cout<<"姓名:"<<m_name<<" 年龄:"<<m_age<<endl; 
}
void test08()
{
	cout<<"************test08**********"<<endl
	 	<<"********类模板成员函数类外实现*******"<<endl;
	Person5<string, int>p("白骨精",999);
	p.showPerson();
}
//1.3.7类模板分文件编写 
//问题:
//类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到
//解决:
//解决1.直接包含.cpp源文件
//解决2.将声明和实现写到同一个文件中,并更改后缀名.hpp..hpp是约定的名称,不是特定 
//1.3.8类模板与友元
//全局函数类内实现-直接在类内声明友元即可
//全局函数类外实现-需要提前让编译器知道全局函数的存在

//类外实现
template<class T1,class T2>
class Person6;
 
template<class T1,class T2> 
void printPerson2(Person6<T1,T2>p)
{
 	cout<<"类外实现--姓名:"<<p.m_name<<" 类外实现--年龄:"<<p.m_age<<endl;
} 

template<class T1,class T2>
class Person6
{
	//全局函数,类内实现
	friend void printPerson(Person6<T1,T2>p)
	{
		cout<<"类内实现--姓名:"<<p.m_name<<" 类内实现--年龄:"<<p.m_age<<endl;;
	 } 
	//全局函数 类外实现
	//加空模板参数列表
	//如果全局函数是类外实现,需要让编译器提前知道这个函数的存在 
	friend void printPerson2<>(Person6<T1, T2> p); 
public:
	Person6(T1 name,T2 age)
	{
		this->m_name = name;
		this->m_age = age;
	}
private:
	T1 m_name;
	T2 m_age;		
 }; 

 void test09()
 {
 	cout<<"************test09**********"<<endl
	 	<<"********全局函数类内实现*******"<<endl;
 	Person6<string, int>p("张飞",456);
	printPerson(p);
	Person6<string, int>p1("曹操",736);
	printPerson2<>(p1); 
 }
 int main()
 {
 	test01();
 	cout<<endl;
 	test02(); 
 	cout<<endl;
 	test03();
 	cout<<endl;
 	test04();
 	cout<<endl;
 	test05();
 	cout<<endl;
 	test06();
 	cout<<endl;
 	test07();
 	cout<<endl;
 	test08();
 	cout<<endl;
 	test09();
 	cout<<endl;
 	system("pause");
 	return 0;
 }
相关推荐
今天我又学废了几秒前
Scala学习记录,List
学习
白子寰11 分钟前
【C++打怪之路Lv14】- “多态“篇
开发语言·c++
小芒果_0116 分钟前
P11229 [CSP-J 2024] 小木棍
c++·算法·信息学奥赛
gkdpjj22 分钟前
C++优选算法十 哈希表
c++·算法·散列表
王俊山IT23 分钟前
C++学习笔记----10、模块、头文件及各种主题(一)---- 模块(5)
开发语言·c++·笔记·学习
-Even-26 分钟前
【第六章】分支语句和逻辑运算符
c++·c++ primer plus
我是谁??1 小时前
C/C++使用AddressSanitizer检测内存错误
c语言·c++
Mephisto.java1 小时前
【大数据学习 | kafka高级部分】kafka中的选举机制
大数据·学习·kafka
南宫生2 小时前
贪心算法习题其三【力扣】【算法学习day.20】
java·数据结构·学习·算法·leetcode·贪心算法
发霉的闲鱼2 小时前
MFC 重写了listControl类(类名为A),并把双击事件的处理函数定义在A中,主窗口如何接收表格是否被双击
c++·mfc