文件操作
对文件操作需要包含头文件<fstream>
文件类型:
文本文件:以文本ASCII码形式储存
二进制文件:以文本的二进制形式储存
操作文件三大类:
ofstream:写操作
ifstream:读操作
fstream:读写操作
写文本文件
步骤:
1创建流对象 ofstream ofs;
2打开文件 ofs.open("文件路径",打开方式);
3写数据 ofs<< "写入的数据"
4关闭文件 ofs.close();
读文件
步骤
1.创建流对象 ifstream ifs;
2.打开文件 ifs.open("文件路径",打开方式)
3.判断是否成功打开
if(!ifs.is_open()){
cout<<"打开失败"<<endl;
return;
}
3.读数据 四种方式
方式1
charnbuf[1024] = {0};
while(ifs >> buf){
cout<<buf<<endl;
}
方式2
char buf[1024] = {0};
while (ifs.getline(buf,sizeof(buf))){
cout<<buf<<endl;
}
方式3
string buf;
while(getline(ifs,buf)){
cout<<buf<<endl;
}
方式4(不推荐)
char c;
while((c = ifs.get())!=EOF) //EOF end of file
{
cout<<c;
}
4.关文件 ifs.close();
模板
函数模板的作用:
建立一个通用函数,其函数返回值类型和形参类型可以不具体指定,用一个虚拟的类型来代表。
语法
typename可以换成class
template<typename T>
函数声明或定义
例子:
template<typename T>
void swapMy(T &a,T &b) {
T temp = a;
a = b;
b = temp;
}
模板使用方式
方式1:自动类型推导
void test() {
//1.自动推导
int a= 10;
int b = 3;
swapMy(a,b);
}
方式2:显示指定类型
void test() {
//2.显式指定类型
int a= 10;
int b = 3;
swapMy<int>(a,b);
}
普通函数与函数模板的区别
普通函数调用可以发生隐式类型转换
int add(int a,int b) {
return a+b;
}
void test01() {
int a = 10;
char b = 'a'; //97
cout<<add(a,b)<<endl; //107
}
函数模板用自动类型推导,不可以发生隐式类型转换
函数模板 用显示指定类型,可以发生隐式类型转换
同名普通函数和函数模板的调用规则
1.如果函数模板和普通函数都可实现,优先普通
2.可以通过空模板参数列表来强制调用函数模板
void swapMy(T &a,T &b) {
T temp = a;
a = b;
b = temp;
}
void swapMy(int a,int b) {
cout<<'a'<<endl;
}
void test03() {
int a=0;
int b=1;
swapMy<>(a,b); //空模板参数列表 强制调用
}
3.如果函数模板可以产生更好的匹配,优先调用函数模板 更好的匹配指的是不用隐式转换
类模板
语法就是模板声明下面跟一个类就行
template<class AgeType,class NameType = string>//NameType 默认为string
class Person {
public:
Person(NameType name,AgeType age) {
this->age = age;
this->name = name;
}
AgeType age;
NameType name;
};
void test02() {
Person<int,string> p1("shi",31);
}
类模板成员函数创建时机
在调用时才创建
类模板对象做函数的参数
1.指定传入类型(常用)
class Person {
public:
Person(NameType name,AgeType age) {
this->age = age;
this->name = name;
}
void showPerson() {
cout<<this->age<<endl;
}
AgeType age;
NameType name;
};
//1.指定传入类型
void printPerson(Person<int,string> &p) {
p.showPerson();
}
void test02() {
Person<int,string> p1("shi",31);
printPerson(p1);
}
2.参数模板化
//2.参数模板化
template<class T1,class T2>
void printPerson2(Person<T1,T2> &p) {
p.showPerson();
}
3.整个类模板化
//整个类模板化
template<class T>
void printPerson3(T &p) {
p.showPerson();
};
类模板与函数模板的区别
类模板没有自动类型推导的使用方式,只能显示指定。
类模板在模板参数列表中可以有默认参数
类模板与继承
当子类继承的父类是一个类模板时,子类在声明的时候要指定出父类中T的类型
因为如果不指定,编译器无法给子类分配内存
如果想灵活指定父类中T的类型,子类也需要变为类模板
template<class T>
class Base {
public:
T a;
};
template<class T1,class T2>
class Son:public Base<T2> {
public:
T1 b;
};
类模板成员函数类外实现
template<class AgeType,class NameType = string>
class Person {
public:
Person(NameType name,AgeType age);
// {
// this->age = age;
// this->name = name;
// }
void showPerson();
// {
// cout<<this->age<<endl;
// }
AgeType age;
NameType name;
};
//构造函数类外实现
template<class AgeType,class NameType>
Person<AgeType,NameType>::Person(NameType name, AgeType age) {
this->age = age;
this->name = name;
}
//成员函数类外实现
template<class AgeType,class NameType>
void Person<AgeType,NameType>::showPerson() {
cout<<this->age<<endl;
}
模板的小练习
//实现通用数组类
//可以对内置数据类型以及自定义数据类型的数据进行存储
//将数组中的数据存储到堆区
//构造函数中可以传入数组的容量
//提供对应拷贝构造函数以及operator=防止浅拷贝问题
//提供尾插法和尾删法对数组中的数据进行增加和删除
//能通过下表访问数组元素
//可以获取数组中当前元素个数和数组容量
template<class T>
class MyArray {
public:
MyArray(int capacity) {
this->Capacity = capacity;
this->Size = 0;
this->pAddress = new T[this->Capacity];
}
~MyArray() {
if(pAddress!=NULL) {
delete[] this->pAddress;
pAddress = NULL;
}
}
MyArray(const MyArray& arr) {
this->Capacity = arr.Capacity;
this->Size = arr.Size;
this->pAddress = new T[arr.Capacity];
for(int i=0;i<this->Size;i++) {
this->pAddress[i] = arr[i];
}
}
MyArray& operator= (const MyArray &arr){
if(this->pAddress!=NULL) {
delete[] this->pAddress;
this->Capacity = 0;
this->Size = 0;
this->pAddress = NULL;
}
this->Capacity = arr.Capacity;
this->Size = arr.Size;
this->pAddress = new T[arr.Capacity];
for(int i=0;i<this->Size;i++) {
this->pAddress[i] = arr[i];
}
}
//尾插法
void Push_Back(cosnt T &value) {
if(this->Capacity == this->Size) {
return;
}
this->pAddress[this->Size] = value;
this->Size++;
}
//尾删法
void Pop_Back() {
if(this->Size == 0) {
return;
}
Size--;
}
T& operator[](int number) {
if(number>=0 && number<Size) {
return pAddress[number];
}
}
private:
T * pAddress; //指向数组
int Capacity; //数组容量
int Size; //数组大小
};