C++ Library(3)



  • C++ Library(3)

    8.结构体 struct(2)

    下面我们来进一步了解结构体

    8.1 构造函数

    我们还是以Point类型为例

    如果我们想要获得一个x=1,y=2Point, 目前可以怎么做?

    Point p;
    p.x = 1, p.y = 2;
    

    这样未免不太优雅, 而且效率上也略有损失(当我们需要赋值的东西更多的时候, 这样的损失更大)

    有方法可以直接「构造」出一个我们想要的Point吗?

    构造函数!

    一个结构体的构造函数是一个「返回这种类型」的函数, 作用上相当于构造了一个此类型, 因而得名「构造函数」(constructor)

    struct Point
    {
        int x, y;
        Point (int xx, int yy) : x (xx), y (yy) {}
    };
    
    Point p1 = Point(1,2);//这样就可以用这种方式来构造Point了, p1就是一个x=1, y=2的Point
    Point p2(1, 3);
    
    • 构造函数是特殊的函数, 函数名等于「类型的名字」, 这里的Point类型的构造函数的名字也叫Point
    • 括号内填你想用来构造一个Point所需的参数(同普通函数)
    • 参数列表后跟一个「初始化列表」, 具体形式为变量名(给它赋的值), 多个「初始化」语句用括号隔开
    • 「初始化列表」之后就是函数体, 这里因为我们没有什么要做的了, 所以只跟了一对空的花括号
    • 构造函数不需要return, 因为默认return的就是构造好了的Point

    当然, 你也可以这么写, 但是不推荐

    struct Point
    {
        int x, y;
        Point (int xx, int yy)
        {
            x = xx, y = yy;
        }
    };
    

    至于为什么, 这就涉及到了「初始化」和「赋值」的区别了, 这里略去. 总之: 尽量使用「初始化列表」的方式来写

    但是, 仅仅这样写构造函数的话, 如果你的程序中还有有类似于这样的语句:

    Point p;
    

    那么就会报错, 因为: 你只定义了「有两个参数的时候的构造函数」, 而这里你没有定义这种情况下Point应该如何构造, 编译器懵逼了, 所以抛出了这个Error

    所以, 我们只需要再添加一个「默认构造函数」(也就是没有任何参数时候的构造函数)就可以了:

    struct Point
    {
        int x, y;
        Point() : x (0), y (0) {}
        Point (int xx, int yy) : x (xx), y (yy) {}
    };
    Point p;//这样默认就是(0, 0)
    

    或者, 还有更加高级一点的方法, 利用「函数参数默认值」:

    struct Point
    {
        int x, y;
        Point (int xx = 0, int yy = 0) : x (xx), y (yy) {}
    };
    

    这样当缺少参数时, xx.yy会默认为0, 也就达到了我们想要的效果

    8.2 重载运算符

    • 运算符是特殊的函数

    所以重载运算符和定义/重载函数是基本一样的语法

    我们往往需要这样的功能, 对一个自定义的结构体数组进行排序, 比如:

    P1051 谁拿了最多奖学金中, 我们可以定义一个「学生类型」:

    struct Student
    {
        string name;
        int final_grade;
        int class_evaluation;
        bool cadres;
        bool western_provinces;
        int papers;
        int scholarship;
    } student[MAXN];
    

    然后我们需要求出拿了最多奖学金的那个人, 那么我们就需要对student数组排序. 那么, 我们就需要知道「如何比较两个student」; 或者说: 我们需要让编译器知道「如何比较两个student」, 再进一步, 我们需要定义student<小于号运算符.

    bool operator < (const Student &a, const Student &b)
    {
        return a.scholarship < b.scholarship;
    }
    

    重载运算符的定义和函数的定义非常相似, 唯一的区别在于「函数名」不是自定义的了, 而是operator <op>的形式, 其中<op>为你想重载的运算符.

    我们都知道, <小于号是一个「二元运算符」, 需要两个参数(来进行比较). 并且返回一个bool值.

    注意: 这里的参数使用了「const引用」, 是为了具有更好的通用性, 记住即可.

    这样, 我们就可以直接调用sort啦:

    sort (student + 1, student + n + 1);
    
    

    同理, 你也可以重载更多的运算符, 比如你可以重载Pointint相加, 你甚至可以重载下标运算符[], 逗号运算符,, 但是请注意, 你不能重载内置类型和内置类型的运算, 比如你不能重载int+int

    9.双向队列 deque

    • queue,priority_queue一样, 包含在<queue>
    • 顾名思义, 支持从队首和队尾插入和删除
    #include <iostream>
    #include <queue>
    
    using namespace std;
    
    int main()
    {
        deque<int> q;
        q.push_front (1); //从队首插入,{1}
        q.push_back (2); //从队尾插入,{1,2}
        q.push_back (3); //{1,2,3}
        q.push_front (4); //{4,1,2,3}
        q.push_back (5); //{4,1,2,3,5}
        q.push_front (6); //{6,4,1,2,3,5}
        q.push_back (7); //{6,4,1,2,3,5,7}
        q.push_front (8); //{8,6,4,1,2,3,5,7}
        while (!q.empty())
        {
            cout << q.front() << ' ' << q.back() << endl;//分别输出队首和队尾
            q.pop_front();//从队首删除
            q.pop_back();//从队尾删除
        }
        return 0;
    }
    
    

    10.<cctype>

    isdigit(char)//判断是否为整数字符'0'-'9'

    isalpha(char)//判断是否为字母字符'a'-'z'

    isupper(char) //判断是否为大写字母字符

    islower(char) //判断是否为小写字母字符

    toupper(char&) //转大写

    tolower(char&) //转小写

    11.<cmath>

    pow(x, n)//求x的n次方, 返回一个浮点数

    log(x)//返回x的自然对数(以e为底的对数)

    log10(x)//返回x的常用对数(以10为底的对数)

    log2(x)//返回x的以2为底的对数

    min(x, y)//返回x和y中的较小值

    思考题1: 实现下列函数, 要求不得调用其它函数(如min, max)、不得使用与逻辑相关的语法(如比较运算符>,<,==; if语句; 三目运算符?:等)

    unsigned int my_max(unsigned int a, unsigned int b)//求两个非负整数的最大值
    {
        
    }
    
    

    解答:

    unsigned int my_max (unsigned int a, unsigned int b)
    {
        return (a * (a / b) + b * (b / a)) / (a / b + b / a);
    }
    
    

    a<b时,a/b=0,所以前面为b*(b/a),后面为b/a,那么结果就是b
    a=b时,a/b=1,所以前面为a+b=2a,后面为2,那么结果就是a
    a>b时,b/a=0,所以前面为a*(a/b),后面为a/b,那么结果就是a

    12.快速读入

    • cin/cout
    • scanf/printf
    • gets/puts

    快速读入非负整数:

    inline int getint()
    {
        int x = 0;
        char c = getchar();
        while (!isdigit (c)) c = getchar();
        while (isdigit (c))
        {
            x = x * 10 + c - 48;
            c = getchar();
        }
        return x;
    }
    
    

    思考题2: 如何实现快速读入整数、浮点数?


 

Copyright © 2018 bbs.dian.org.cn All rights reserved.

与 Dian 的连接断开,我们正在尝试重连,请耐心等待