普通算法题不太涉及的C++知识点(五):文件操作,模板

1. 文件操作:

C++对文件操作需要调用库函数:

#include <fstream>

文件类型分为文本文件和二进制文件。

1.1 读写文本文件:

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

void test(){
	ofstream ofs1;
	ofs1.open("text1.txt", ios::out);
	ofs1 << "hello" << endl;
	ofs1 << "world" << endl;
	ofs1.close();

	ifstream ifs1;
	ifs1.open("text1.txt", ios::in);
	if(!ifs1.is_open()){
		cout << "error" << endl;
		return;
	}
	//读数据方法:
	//第一种:
	char buffer[1024] = {0};
	while(ifs1 >> buffer){
		cout << buffer << endl;
	}

	//第二种:
	char buffer[1024] = {0};
	while( ifs1.getline(buffer, sizeof(buffer)) ){
		cout << buffer << endl;
	}

	//第三种:
	string buffer;
	while( getline(ifs1, buffer) ){
		cout << buffer << endl;
	}
	
	ifs1.close();
}

int main(){
	test();
	return 0;
}

1.2 读写二进制文件:

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

class person(){
public:
	char m_name[64];
	int m_age;
};

void test(){
	ofstream ofs;
	ofs.open("text.txt", ios::out|ios::binary);
	person p = {"bob", 18};
	ofs.write( (const char*)&p, sizeof(person) );
	ofs.close();

	ifstream ifs;
	ifs.oepn("text.txt", ios::in|ios::binary);
	if(!is_open()){
		cout << "文件打开失败" << endl;
		return;
	}
	person p;
	ifs.read((char*)&p, sizeof(person));
	ifs.close();
}

int main(){
	test();
	return 0;
}

2. 模板:

模板就是建立通用的模具,大大提高复用性。

2.1 函数模板:

建立一个通用函数,其函数返回值和形参列表可以不具体制定,用一个虚拟的类型来代表。

2.1.1 函数模板语法:

template<typename T>
函数声明或定义

eg:

//各种数据类型交换函数:
template<typename T>
void myswap(T &a, T &b){
	T temp = a;
	a = b;
	b = temp;
}

void test(){
	int a = 10;
	int b = 20;
	//使用模板的两种方法:
	//1.自动类型推导:
	myswap(a, b);
	//2.显示指定类型:
	myswap<int>(a, b);
}

2.1.2 函数模板案例——数组排序:

template<class T>
void myswap(T &a, T &b){
	T temp = a;
	a = b;
	b = temp;
}

template<class T>
void mysort(T arr[], int length){
	for(int i=0;i<length;i++){
		int max = i;
		for(int j=i+1;j<length;j++){
			if(arr[max] < arr[j]){
				max = j;
			}
		}
		if(max!=i){
			myswap(arr[max], arr[i]);
		}
	}
}

template<class T>
void myprint(T arr[], int length){
	for(int i = 0;i<length;i++){
		cout << arr[i] << " ";
	}
	cout << endl;
}

void test(){
	char c[] = "qsefrgth";
	int num = sizeof(c)/sizeof(char);
	mysort(c, num);
	myprint(c, num);

	int n[] = {1,3,5,3,2,7,0};
	int num2 = sizeof(n)/sizeof(int);
	mysort(n, num2);
	myprint(n, num2);
}

2.1.3 普通模板和函数模板的区别:

普通函数调用时可以发生自动类型转换;
函数模板调用时,如果使用自动类型推导,不会发生自动类型转换;
函数模板调用时,如果使用指定类型方式,会发生自动类型转换。

2.1.4 普通函数和函数模板的调用规则:

优先调用普通函数;
可以通过空模板参数列表强制调用函数模板;
函数模板也可以重载;
如果函数模板能产生更好的匹配,则优先调用函数模板。

void myprint(int a, int b){
	cout << 1 << endl;
}

template<class T>
void myprint(T a, T b){
	cout << 2 << endl;
}

void test(){
	int a = 10;
	int b = 20;
	myprint(a, b);  //输出1,优先调用普通函数
}
void myprint(int a, int b);

template<class T>
void myprint(T a, T b){
	cout << 2 << endl;
}

void test(){
	int a = 10;
	int b = 20;
	myprint(a, b);  //报错,优先调用普通函数
}
void myprint(int a, int b){
	cout << 1 << endl;
}

template<class T>
void myprint(T a, T b){
	cout << 2 << endl;
}

void test(){
	int a = 10;
	int b = 20;
	myprint<>(a, b);  //输出2,通过空模板参数列表,强制调用函数模板
}

函数模板的重载:

template<class T>
void myprint(T a, T b){
	cout << 1 << endl;
}

template<class T>
void myprint(T a, T b, T c){
	cout << 2 << endl;
}

void test(){
	int a = 10;
	int b = 20;
	myprint(a, b, 100);  //输出2
}

函数模板产生更好的匹配:

void myprint(int a, int b){
	cout << 1 << endl;
}

template<class T>
void myprint(T a, T b){
	cout << 2 << endl;
}

void test(){
	char c1 = 'a';
	char c2 = 'b';
	myprint(c1, c2);  //输出2,因为函数模板产生了更好匹配
}

2.2 模板的局限性:

模板的通用性不是万能的。
使用模板具体化来处理自定义数据类型:

class person{
public:
	person(string name, int age){
		m_name = name;
		m_age = age
	}
	string m_name;
	int m_age;
};

template<class T>
bool compare(T &a, T &b){
	if(a==b){
		return true;
	}
	return false;
}

//利用具体化版本实现person对比
template<> bool compare(person &a, person &b){
	if(a.m_name==b.m_name && a.m_age==b.m_age){
		return true;
	}
	return false;
}

void test(){
	int a = 10;
	int b = 20;
	cout << compare(a, b) << endl;  //正常输出

	person p1("Tom", 10);
	person p2("Tom", 10);
	cout << compare(p1, p2) << endl;  //没有具体化版本时运行出错,有则正确输出
}

2.3 类模板:

2.3.1 类模板的基本语法:

建立一个通用类,类中成员的数据类型可以不具体指定。

template<class T>

eg:

template<class nameType, class ageType>
class person{
public:
	person(nameType name, ageType age){
		m_name = name;
		m_age = age;
	}

	nameType m_name;
	ageType m_age; 
};

void test(){
	person<string, int> p1("bob", 12);
}

2.3.2 类模板与函数模板的区别:

类模板没有自动类型推导的使用方法;
类模板在模板参数列表中可以有默认参数。

template<class nameType, class ageType = int>
class person{
public:
	person(nameType name, ageType age){
		m_name = name;
		m_age = age;
	}

	nameType m_name;
	ageType m_age; 
};

void test(){
	//person p1("bob", 12);   //错误
	person<string, int> p1("bob", 12);  //正确
	person<string> p2("bob", 12);  //正确
}

2.3.3 类模板中成员函数创建时机:

普通类中的成员函数一开始就可以创建;
类模板中的成员函数在调用时才创建。

2.3.4 类模板对象做函数参数:

一共有三种传入方式:
指定传入的类型;(最常用)
参数模板化;
整个类模板化。

template<class T1, class T2>
class person{
public:
	person(T1 name, T2 age){
		m_name = name;
		m_age = age;
	}
	void show(){
		cout << m_name << " " << m_age << endl;
	}

	T1 m_name;
	T2 m_age; 
};

//指定传入类型:(最常用)
void print1(person<string, int> &p){
	p.show();
}

//参数模板化:
template<class T1, class T2>
void print2(person<T1, T2> &p){
	p.show();
}

//整个类模板化:
template<class T>
void print3(T &p){
	p.show();
}

void test(){
	person<string, int> p1("bob", 13);	
	print1(p1);
	print2(p1);
	print3(p1);
}

2.3.5 类模板与继承:

当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型;
如果不指定,编译器无法给子类分配内存;
如果想灵活指出父类中T的类型,子类也需变为类模板。

template<class T>
class base{
	T m;
};

class son : public base<int>{
	
};

template<class T1, class T2>
class son2 : public base<T1>{
	T2 obj;
};

2.3.6 类模板成员函数类外实现:

template<class T1, class T2>
class person{
public:
	person(T1 name, T2 age);
	//{
	//	m_name = name;
	//	m_age = age;
	//}
	void show();
	//{
	//	cout << m_name << endl;
	//	cout << m_age << endl;
	//}

	T1 m_name;
	T2 m_age;
};

template<class T1, class T2>
person<T1, T2>::person(T1 name, T2 age){
	m_name = name;
	m_age = age;
}

template<class T1, class T2>
void person<T1, T2>::show(){
	cout << m_name << endl;
	cout << m_age << endl;
}

2.3.7 类模板分文件编写:

person.h

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

template<class T1, class T2>
class person{
public:
	person(T1 name, T2 age);
	void show();

	T1 m_name;
	T2 m_age;
};

person.cpp

#include "person.h"

template<class T1, class T2>
person<T1, T2>::person(T1 name, T2 age){
	m_name = name;
	m_age = age;
}

template<class T1, class T2>
void person<T1, T2>::show(){
	cout << m_name << endl;
	cout << m_age << endl;
}

person.hpp

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

template<class T1, class T2>
class person{
public:
	person(T1 name, T2 age);
	void show();

	T1 m_name;
	T2 m_age;
};
template<class T1, class T2>
person<T1, T2>::person(T1 name, T2 age){
	m_name = name;
	m_age = age;
}

template<class T1, class T2>
void person<T1, T2>::show(){
	cout << m_name << endl;
	cout << m_age << endl;
}

chengxu.cpp

//第一种方法,直接包含源文件:
//#include "person.cpp"
//第二种方法,将h和cpp内容写在一起,后缀写为hpp:
#include "person.hpp"

int main(){
	......
}

2.3.8 类模板与友元:

类内实现:

template<class T1, class T2>
class person{
//全局函数类内实现:
	friend void myprint(person<T1, T2> p){
		cout << p.m_name << endl;
		cout << p.m_age << endl;
	}

public:
	person(T1 name, T2 age){
		m_name = name;
		m_age = age;
	}
private:
	T1 m_name;
	T2 m_age;
};

类外实现:

#include <iostream>
#include <string>

using namespace std;

template<class T1, class T2>
class person;

//类外实现:
template<class T1, class T2>
void myprint2(person<T1, T2> p){
	cout << p.m_name << endl;
	cout << p.m_age << endl;
}

template<class T1, class T2>
class person{
//全局函数类外实现:
	friend void myprint2<>(person<T1, T2> p);

public:
	person(T1 name, T2 age){
		m_name = name;
		m_age = age;
	}
private:
	T1 m_name;
	T2 m_age;
};

int main()
{
    person<string, int> p1("bob", 12);
    myprint2(p1);
    return 0;
}

2.3.9 类模板案例——数组类封装:

myarray.hpp

#include <iostream>

using namespace std;

template<class T>
class myarray{
public:
	myarray(int capacity){
		m_capacity = capacity;
		m_size = 0;
		paddress = new T[m_capacity];
	}
	maarray(const myarray &arr){
		m_capacity = arr.m_capacity;
		m_size = arr.m_size;
		//浅拷贝:
		//paddress = arr.paddress
		//深拷贝:
		paddress = new T[arr.m_capacity];
		for(int i = 0;i<m_size;i++){
			paddress[i] = arr.paddress[i];
		}
	}
	~myarray(){
		if(paddress!=NULL){
			delete paddress;
			paddress = NULL;
		}
	}

    //尾插法
	void push_back(const T &val){
		//判断容量是否足够:
		if(m_capacity==m_size){
			cout << "insert error" << endl;
			return;
		}
		paddress[m_size] = val;
		m_size++;
	}
	//尾删法:
	void pop_back(){
		//让用户访问不到最后一个元素即可
		if(m_size==0){
			return;
		}
		m_size--;
	}
	//通过下标访问元素:
	T& operator[](int index){
		return paddress[index];
	}
	//返回数组容量:
	int getcapacity(){
		return m_capacity;
	}
	int getsize(){
		return m_size;
	}


	//operator=防止浅拷贝:
	myarray& operator=(const myarray& arr){
		if(paddress!=NULL){
			delete paddress;
			paddress = NULL;
		}
		m_capacity = arr.m_capacity;
		m_size = arr.m_size;
		paddress = new T[arr.m_capacity];
		for(int i = 0;i<m_size;i++){
			paddress[i] = arr.paddress[i];
		}
		return *this;
	}

private:
	T *paddress;
	int m_capacity;
	int m_size;
};

main.cpp

#include "myarray.hpp"

void test(){
	myarray<int> arr1(5);
	for(int i = 0;i<5;i++){
        arr1.push_back(i);
	}

	for(int i = 0;i<5;i++){
        cout << arr1[i] << endl;
	}

	//cout << arr1.getsize() << endl;
	//cout << arr1.getcapacity() << endl;
	arr1.pop_back();
	arr1.pop_back();

	for(int i = 0;i<arr1.getsize();i++){
        cout << arr1[i] << endl;
	}
}

int main(){
	test();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值