cpp学习记录06:文件操作与模板

文件操作

对文件操作需要包含头文件<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; //数组大小
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值