C++学习(五)

   函数模板与类模板:{      '将类型定义为参数 实现代码重用机制的工具'

       函数模板:{

            建立一个通用函数 其函数返回类型和形参类型不具体指定 用一个虚拟的类型来代表 具体形式如下: {

                

template <typename 类型参数>  // 或 template <class 类型参数>

返回类型 函数名(模板形参表)

{

    函数体

}

            }

#include <iostream>
using namespace std;

template <typename T>
T Max(T *arry, int numb = 0)
{
    T max = arry[0];
    for(int i = 1; i < numb; i++)
    {
        if(arry[i] > max)
        {
            max = arry[i];
        }
    }
    return max;
}

int main()
{
    int arry[] = {1, 2, 9, 4, 5};
    cout << "The max number is: " << Max(arry, 5) << endl;
    double arry1[] = {1.1, 4.2, 3.3};
    cout << "The max number is: " << Max(arry1, 3) << endl;

    return 0;
}

            'template' -- 声明模板的关键字  '类型参数' -- 常用T 、type等 使用函数模板时 必须将类型实例化

            类型参数前需加关键字'typename或class' 表示一个虚拟的类型名

#include <iostream>
using namespace std;

template <class T>
T Max(T a, T b)
{
    return (a > b)? a : b;
}

template <class T>
T MAX(T a, T b, T c)
{
    T max = a > b? a : b;
    max = max > c? max : c;
    return max;
}

int main()
{
    cout << "The two number max is: " << Max(3, 5) << endl;
    cout << "The three number max is: " << MAX(9, 5, 7) << endl;

    return 0;
}

            在函数模板中允许使用多个类型参数 template定义部分的每个类型参数前必须有关键字'typename或class'

            在template语句与函数模板定义语句之间不允许插入别的语句

            函数模板与同名的非模板函数也可以重载

                调用的顺序是:首先寻找一个参数完全匹配的非模板函数 如果找到了就调用它

                            若没有找到 则寻找函数模板 将其实例化 产生一个匹配的模板参数 若找到了 就调用它

       }

       类模板:{

            建立一个通用类 其数据成员 成员函数的返回类型和形参类型不具体指定 用一个虚拟的类型来代表

            使用类模板定义对象时 系统会根据实参的类型来取代类模板中虚拟类型 从而实现不同类的功能

            eg:{

        

    template <typename T>

    class Classname{

        private:

            T data1, data2, data3;

        public:

            Classname(T a, T b, T c) : data1(a), data2(b), data3(c) {}

            T sum()

            {

                return data1 + data2 + data3;

            }

     };

            }

            上面的例子  成员函数是定义在类体内的 类模板中的成员函数也可以在类模板体外定义 若成员函数中有类型参数存在 则C++有一些特殊的规定:

                需要在成员函数定义之前进行模板声明

                在成员函数名前要加上 ' 类名<类型参数>:: '

           在类模板体外定义的成员函数的一般形式如下 : {

template <typename T>

函数类型 类名<类型参数>::成员函数名(形参表)

{

    函数体

}

            则上述例子中的sum函数可以改写如下:

template <typename T>

T Classname<T>::sum()

{

    return data1 + data2 + data3;

}

            }

       }

   }

   C++的输入和输出:{     '以字节流形式实现'

       优点: 完全支持c语言的输入输出系统 建立面向对象的输入输出系统 比c更安全可靠

            可重载 <<  >> 运算符 实现用户自定义类型的输入输出 书写形式简单清晰 可读性强

       C++的流库及其基本结构: {

            '流' 指数据从一个源流到一个目的的抽象 从流中提取数据称为输入操作(提取操作) 向流中添加数据称为输出操作(插入操作)

            输入: 字节流从输入设备流向内存   输出: 字节流从内存流向输出设备

            文件和字符串也可以看成有序的字节流 分别称为文件流和字符串流

            常用的输入输出头文件:{

                'iostream' 包含输入/输出流进行操作所需的基本信息

                'fstream'   用于用户管理文件的I/O操作   (针对磁盘文件的操作)

                'strstream' 用于字符串流的I/O操作       (针对内存字符串空间的I/O操作)

                'iomanip'   用于输入/输出的格式控制

            }

            用流定义的对象称为流对象 以下是几个预定义的流对象:

                'cin'  标准输入流对象  从标准输入设备读取数据

                'cout'  标准输出流对象  向标准输出设备输出数据

                'cerr'  标准错误流对象  向标准错误设备输出错误信息

                'clog'  缓冲型标准错误流对象  向缓冲区输出错误信息

            使用istream和类ostream流对象的一些成员函数  实现字符的输出和输入: {

                'put()函数'         cout.put(单字符/字符形变量/ASCII码);

                'get()函数'         cin.get(字符型变量)   get()函数在读入数据时可包括空白符 提取运算符'>>'在默认情况下拒绝接受空白符

                'getline()函数'     cin.getline(字符数组, 字符个数n, 终止标志字符)  cin.getline(字符指针, 字符个数n, 终止标志字符)

                'ignore()函数'      cin.ignore(n, 终止字符)  ignore()函数的功能是跳过输入流中n个字符(默认个数1) 或在遇到指定的终止字符(默认终止字符是EOF)时提前结束

            }

            预定义类型输入/输出的格式控制:{

                流成员函数进行输入/输出格式控制 {

                    'setf()函数'        用于设置流的状态标志 如setf(ios::scientific)

                    'unsetf()函数'      用于清除流的状态标志

                    'width()函数'       用于设置域宽

                    'precision()函数'   用于设置实数的精度

                    'fill()函数'        用于设置填充字符

                }

            }

            使用预定义的操作符进行输入/输出格式控制

            使用用户自定义的操作符进行输入/输出格式控制 {

                若输出流定义操作符函数 则形式如下

                ostream &操作符名(ostream &stream)

                {

                    自定义代码

                    return stream;

                }

                若为输入流定义操作符函数 形式如下

                istream &操作符名(istream &stream)

                {

                    自定义代码

                    return stream;

                }

            }

                

#include <iostream>
#include <iomanip>

using namespace std;

ostream &output(ostream &stream)
{
    stream.setf(ios::left);    //设置输出左对齐
    stream << setw(10) << hex << setfill('-');  //将输出 设置域宽为10 十六进制 填充字符为-
    return stream;
}

int main()
{
    cout << 123 << endl;
    cout << output << 123 << endl;

    return 0;
}

       }

       文件的输入/输出:{    '文件' --存放在外部介质上的数据的集合

            '文件流'  -- 以外存文件为输入/输出对象的数据流  输出文件流是从内存流向外存文件的数据 输入文件流是从外存流向内存的数据

            根据文件中数据的组织形式 文件分为两类: 文本文件和二进制文件

            进行文件操作的一般步骤如下: {

                定义一个流对象 -- 建立文件 -- 进行读写操作 -- 关闭文件

                三个文件流类:

                    istream  -- 输入文件流类

                    ofstream -- 输出文件流类

                    fstream  -- 输入/输出文件流类

                执行文件输入/输出的一般步骤如下:{

                    含头文件fstream

                    建立流对象

                    使用open()函数打开文件

                    进行读写操作

                    使用close()函数关闭文件

                }

            }

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
    ofstream fout("./test.txt", ios::out);
    if (!fout) {
        cout << "Cannot open output file." << endl;
        exit(1);
    }
    fout << "I am a student.";
    fout.close();

    ifstream fin("./test.txt", ios::in);
    if (!fin) {
        cout << "Cannot open input file." << endl;
        exit(1);
    }
    char str[80];
    fin.getline(str, 80);
    cout << str << endl;
    fin.close();

    return 0;
}

            文件打开方式: {

                    ios::in  -- 以读方式打开文件

                    ios::out -- 以写方式打开文件

                    ios::ate -- 打开文件时指针指向文件末尾

                    ios::app -- 以追加方式打开文件

                    ios::trunc -- 若文件已存在 则清空文件内容

                    ios::binary -- 以二进制方式打开文件

            }

            二进制文件读写

                用read()函数和write()函数读写二进制文件 格式如下:

                    inf.read(char *buf, int len);

                    outf.write(const char* buf, int len );

#include <iostream>
#include <fstream>

using namespace std;
int cput()
{
    ofstream outf("test.txt", ios::out);
    if(!outf) {
        cout << "Cannot open output file." << endl;
        exit(1);
    }

    char ch = 'a';
    for(int i = 0; i< 26; i++) {
        outf.put(ch);
        ch++;
    }

    outf.close();
    return 0;
}

int cget()
{
    ifstream inf("test.txt", ios::in);
    if(!inf) {
        cout << "Cannot open input file." << endl;
        exit(1);
    }

    char ch;
    while(inf.get(ch)) {
        cout << ch << ' ';
    }
    cout << endl;

    inf.close();
    return 0;
}

int main()
{
    cput();
    cget();

    return 0;
}

            检测文件结束:

                在文件结束的地方有一个标志位 'EOF' 采用文件流方式读取文件时 使用eof()函数 可检测到该结束符

                若该函数返回'非零值' 则到达文件末尾 否则未到文件末尾

                eg:{

                        

    ifstream ifs;

    ...

    if(!ifs.eof()) {

        cout << "文件未到末尾" << endl;

    }

                   还有一个检测方法就是检查该流对象是否为零 为零表示文件结束

          ifstream ifs;

          ···

          if (!ifs){

              cout << "文件结束" << endl;

          }

          ···

                    检测文件流对象的某些成员函数的返回值是否为0 为0表示该流到达了末尾

                    while (cin.get(ch))

                        cut.put(ch);

                }

#include <iostream>
#include <fstream>

using namespace std;

struct strList {
    char course[15];
    int score;
};

int main()
{
    strList obj[2] = {{"C++", 90}, {"Java", 85}};
    ofstream outf("test.txt", ios::binary);    //以二进制格式打开文件
    if(!outf) {
        cout << "Cannot open output file." << endl;
        // exit(1);
        abort();
    }

    for(int i = 0; i< 2; i++) {
        outf.write((char*) &obj[i], sizeof(obj[i]));
    }
    outf.close();

    ifstream inf("test.txt", ios::binary);
    if(!inf) {
        cout << "Cannot open input file." << endl;
        abort();
    }

    for(int i = 0; i< 2; i++) {
        inf.read((char*) &obj[i], sizeof(obj[i]));
        cout << "Course: " << obj[i].course << " Score: " << obj[i].score << endl;
    }
    inf.close();

    return 0;
}

                键盘上输入字符时 其结束符是Ctrl+Z  按下【Ctrl+Z】组合键  eof()函数返回的值为真

                is_open() 函数:

                    用于检测文件流对象是否已打开 若已打开 返回true 否则返回false

                    eg:{

                        

        ifstream ifs("test.txt");

        if(ifs.is_open()){

        cout << "文件已打开" << endl;

                     }

                fail() 函数:

                    用于检测文件流对象的状态 若文件流对象发生错误(failbit or badbit被置为) 则返回true 否则返回false

                    failbit -- 发生非致命错误 一般为软件错误 可挽回     badbit -- 发生致命错误 一般为硬件或系统底层错误 不可挽回

                    eg:{

                        

        ifstream ifs("test.txt");

        if(ifs.fail()){

            cout << "文件打开失败" << endl;

        }

                    }

                bad()函数:

                    用于检测文件流对象的状态 若文件流对象发生致命错误(badbit被置为) 则返回true 否则返回false

                    eg:{

        ifstream ifs("test.txt");

        if(ifs.bad()){

            cout << "文件流发生致命错误" << endl;

        }

                    }

                good()函数:

                    用于检测文件流对象的状态 若文件流对象处于正常状态() 则返回true 否则返回false

        eg:{

                



        ifstream ifs("test.txt");

        if(ifs.good()){

            cout << "文件流处于正常状态" << endl;

        }

         }

                clear()函数:

                    用于清除文件流对象的状态 若文件流对象发生错误 则调用clear()函数 则文件流对象的状态恢复正常

                    eg:{

     ifstream ifs("test.txt");

     if(ifs.fail()){

         ifs.clear();

         cout << "文件流发生错误" << endl;

     }

                    }

       }

   }

   异常处理与命名空间:{

       异常处理:{

            常见错误: 编译时错误  主要是语法错误

                     运行时错误  统称为异常

            如果在执行一个函数的过程中出现异常 可以不在本函数中立即处理 而是发出一个信息 传给它的上一级处理(即调用函数)

            若上一级函数也不能处理 则逐级上传 若到最高一级仍无法处理 则运行系统将自动调用系统函数'terminate()' 由它调用'abort()'终止程序

            catch(捕获异常) 、throw(抛出异常)、try(异常处理块)

            eg:{

try{

         string msg("This is a test exception");

         throw msg;

 }catch(const string &e){

         printf("exception = %s",e.c_str());

}

            }

       }

        命名空间:{

           namespace(命名空间)

           自行命名的内存区域  将各命名空间中声明的标识符与该命名空间标识符建立关联 保证不同命名空间的同名标识符不发生冲突

           eg: {

        namespace myspace{

                int x = 10;

        }



        int main(){

                myspace::x = 20;

                return 0;

        }

               }

        }

        c++使用不带扩展名的头文件: 如 #inlcude <cstring>

#include <iostream>
#include <cmath>

using namespace std;

double triangle(double a, double b, double c)
{
    double s = (a + b + c)/2;
    if(a+b <= c || a+c <= b || b+c <= a) {
        throw 1.0;   //抛出double异常
    }
    return sqrt(s * (s-a) * (s-b) * (s-c));
}

int main()
{
    double zozoA, zozoB, zozoC;
    try{
        cout << "Enter three sides of a triangle: " << endl;
        cin >> zozoA >> zozoB >> zozoC;
        if(zozoA <= 0 || zozoB <= 0 || zozoC <= 0) {
            throw 1;   //抛出int异常
        }
        if(zozoA >0 && zozoB >0 && zozoC >0){
            cout << "The area of the triangle is: " << triangle(zozoA, zozoB, zozoC) << endl;
        }
    }catch(double){
        cout << "Invalid input, please enter positive numbers." << endl;
    } catch(int){
        cout << "边长小于0" << endl;
    }

    return 0;
}

   }





 

   STL标准模板库 {

        STL(Standard Template Library) -- 标准模板库 是一个模板集合 包含了常用的数据结构和算法

        'vector' 容器:{

            与数组相似 包含一组地址连续的存储单元 可进行查询、插入、删除等操作

            头文件: #include <vector>

            vector<类型> 变量名;

                eg: vector<int> vec;   // 声明一个int类型的vector

                    vector<vector<string>> file;  //该向量的元素是vector对象

            vector对象初始化:

                vector<T> vec1;               // 默认初始化 元素类型为T

                vector<T> vec2(vec1);         // 拷贝初始化 等价于 vec2 = vec1

                vector<T> vec3(n, val);       // 元素个数为n 值均为val 类型为T

                vector<T> vec4(n);            // 元素个数为n 默认值 类型为T

                vector<T> vec5{a,b,c,d,...};  // 初始化多个元素 等价于vec5 = {a,b,c,d,...}

            'push_back()函数' 向vector中添加元素

                eg:{

                    vector<int> vec;

                    vec.push_back(10);  // 向vec中添加元素10

                }

                注释: vector下标可用于访问已存在的元素 但不能用于添加元素 当vector是空时 只能用push_back()添加或访问元素

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> zoVec;
    zoVec.insert(zoVec.begin(), 99);
    zoVec.insert(zoVec.begin(), 88);
    zoVec.insert(zoVec.end(), 77);
    zoVec.push_back(695);

    cout << "当前zoVec中的元素为: " << endl;
    for(int i = 0; i < zoVec.size(); i++){
        cout << zoVec[i] << " ";
    }
    cout << endl;

    cout << zoVec.at(2) << endl;
    zoVec.erase(zoVec.begin());
    zoVec.pop_back();

    cout << "现在zoVec中的元素为: " << endl;
    for(int i = 0; i < zoVec.size(); i++){
        cout << zoVec[i] << " ";
    }
    cout << endl;

    return 0;
}

        }

        'list' 容器:{

            头文件: #include <list>

            list<类型> 变量名;

                eg: list<int> lst;   // 声明一个元素类型为int的list

        #include <iostream>
        #include <list>

        using namespace std;

        int main()
        {
            list<int> zoList;
            list<int>::iterator niter;  // 定义迭代器 指向int类型元素
            zoList.push_back(123);
            zoList.push_back(456);
            zoList.push_back(789);

            cout << "链表内容 : " << endl;
            for(niter = zoList.begin(); niter != zoList.end(); niter++)
                cout << *niter << " ";
            cout << endl;

            zoList.reverse();  // 反转链表

            cout << "反转链表内容 : " << endl;
            for(niter = zoList.begin(); niter != zoList.end(); niter++)
                cout << *niter << " ";
            cout << endl;

            zoList.reverse();

            return 0;
        }

        }

        'stack' :{

            头文件: #include <stack>

            stack<类型> 变量名;

                eg: stack<int> stk;   // 声明一个元素类型为int的stack

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

int main()
{
    stack<int> zoSt;
    int zoNum = 100;
    cout << "100的八进制为: ";
    while(zoNum) {
        zoSt.push(zoNum % 8);
        zoNum /= 8;
    }

    int zoS;
    while(!zoSt.empty()) {
        zoS = zoSt.top();
        cout << zoS;
        zoSt.pop();
    }
    cout << endl;

    return 0;
}

        }

        'queue' :{

            头文件: #include <queue>

            queue<类型> 变量名;

                eg: queue<int> que;   // 声明一个元素类型为int的queue

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

int main()
{
    queue<int> zoQue;
    for(int i = 0; i<10; i++)
        zoQue.push(i*3 + i);

    while(!zoQue.empty()){
        cout << zoQue.front() << " ";
        zoQue.pop();
    }
    cout << endl;

    return 0;
}

        }

        'priority_queue' 优先队列:{

            头文件: #include <queue>

            priority_queue<类型> 变量名;

                eg: priority_queue<int> pq;   // 声明一个元素类型为int的优先队列

#include <iostream>
#include <queue>
#include <functional>
#include <cstdlib>
#include <ctime>

using namespace std;

int main()
{
    priority_queue<int> zoPq;
    srand((unsigned)time(0));
    for(int i=0; i < 6; i++) {
        int zoR = rand();
        cout << zoR << " ";
        zoPq.push(zoR);
    }
    cout << endl;

    cout << "优先队列中的元素: " << endl;
    for(int i=0; i < 6; i++) {
        cout << zoPq.top() << " ";
        zoPq.pop();
    }

    return 0;
}

        }

        'deque' 双端队列:{

            push_back();

            push_front();

            insert();

            pop_back();

            pop_front();

            erase();

            begin();

            end();

            rbegin();

            rend();

            size();

            maxsize();

        }

        'set' :{

            头文件: #include <set>

            set<类型> 变量名;

                eg: set<int> st;   // 声明一个元素类型为int的set

#include <iostream>
#include <set>
#include <string>

using namespace std;

int main()
{
    set<string> zoSet;
    zoSet.insert("my");
    zoSet.insert("hair");
    zoSet.insert("wet");
    if(zoSet.count("my") != 0) {
        cout << "Existential element : my " << endl;
    }

    set<string>::iterator zoIter;
    for(zoIter = zoSet.begin(); zoIter != zoSet.end(); zoIter++) {
        cout << *zoIter << " ";
    }
    cout << endl;

    return 0;
}

        }

        'map' :{

             头文件: #include <map>

             map<类型1,类型2> 变量名;

                eg: map<string,int> mp;   // 声明一个元素类型为string,值类型为int的map

#include <iostream>
#include <map>
#include <string>

using namespace std;

int main()
{
    map<string, int> zoMap;
    zoMap["apple"] = 100;
    zoMap["banana"] = 200;
    zoMap["orange"] = 300;
    if(zoMap.count("apple")) {
        cout << "The price of apple is: " << zoMap.at("apple") << endl;
        // cout << "The price of apple is: " << zoMap["apple"] << endl;
    }

    return 0;
}


 

        }

}

  • 17
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值