当前位置: 首页 > news >正文

《C++ Primer Plus》第18章:探讨 C++ 新标准(8)

  1. 使用大括号括起的初始化列表语法重写下述代码。重写后的代码不应使用数组 ar:

    class Z200 {
    private:int j;char ch;double z;
    public:Z200(int jv, char chv, zv) : j(jv), ch(chv), z(zv) {}
    ...
    };double x = 8.8;
    std::string s = "What a bracing effect!";
    int k(99);
    Z200 zip(200, 'Z', 0.675);
    std::vector<int> ai(5);
    int ar[5] = { 3, 9, 4, 7, 1 };
    for (auto pt = ai.begin(), int i = 0; pt != ai.end(); ++pt, ++i)*pt = ai[i];
    

    答:

    class Z200 {
    private:int j;char ch;double z;
    public:Z200(int jv, char chv, zv) : j(jv), ch(chv), z(zv) {}
    ...
    };double x {8.8};
    std::string s { "What a bracing effect!" };
    int k{99};
    Z200 zip{200, 'Z', 0.675};
    std::vector<int> ai  { 3, 9, 4, 7, 1 };
    
  2. 在下述简短的程序中,哪些函数调用不对?为什么?对于合法的函数调用,指出其引用参数指向的是什么。

    #include <iostream>
    using namespace std;double up(double x) { return 2.0 * x; }
    void r1(const double &rx) { cout << rx << endl; }
    void r2(double &rx) { cout << rx << endl; }
    void r3(double &&rx) {cout << rx << endl; }int main() {double w = 10.0;r1(w);r1(w+1);r1(up(w));r2(w);r2(w+1);r2(up(w));r3(w);r3(w+1);r3(up(w));return 0;
    }
    

    答:

    r1(w)合法,形参 rx 指向 w。
    r1(w+1)合法,形参 rx 指向一个被初始化为 w+1 的临时变量。
    r1(up(w))合法,形参 rx 指向一个被初始化为 up(w) 返回值的临时变量。
    r2(w)合法,形参 rx 指向 w。
    r2(w+1)非法,因为 w+1 是一个右值。
    r2(up(w))非法,因为 up(w) 的返回值是一个右值。
    r3(w)非法,因为右值引用不能指向左值(如w)。
    r3(w+1)合法,rx指向表达式w+1的临时拷贝。
    r3(up(w))合法,rx 指向 up(w) 的临时返回值。
    
  3. a. 下述简短的程序显示什么?为什么?

    #include<iostream>
    using namespace std;double up(double x) { return 2.0 * x; }void r1(const double &rx) { cout << "const double & rx\n"; }
    void r1(double &rx) { cout << "double & rx\n"; }int main() {double w = 10.0;r1(w);r1(w+1);r1(up(w));return 0;
    }
    

    答:

    double & rx
    const double &rx
    const double &rx
    

    w 是左值,与左值引用匹配,w+1和up(w)是右值,但const 引用可以构建关于它们的临时变量,然后指向临时变量。

    b. 下述简短的程序显示什么?为什么?

    #include<iostream>
    using namespace std;double up(double x) { return 2.0 * x; }void r1(double &rx) { cout << "double & rx\n"; }
    void r1(double &&rx) { cout << "double && rx\n"; }int main() {double w = 10.0;r1(w);r1(w+1);r1(up(w));return 0;
    }
    

    答:

    double & rx
    double && rx
    double && rx
    

    左值引用与左值实参 w 匹配,而右值引用与两个右值实参匹配。

    c. 下述简短的程序显示什么?为什么?

    #include<iostream>
    using namespace std;double up(double x) { return 2.0 * x; }void r1(const double &rx) { cout << "const double & rx\n"; }
    void r1(double &&rx) { cout << "double && rx\n"; }int main() {double w = 10.0;r1(w);r1(w+1);r1(up(w));return 0;
    }
    

    答:

    const double & rx
    double && rx
    double && rx
    

    const 左值引用与左值实参匹配,而右值引用与两个右值实参匹配。

    总之,非const左值形参,只能匹配左值实参;非const 右值形参只能匹配右值实参;const 左值可与左值或右值形参匹配,但如果与前两种方式同时存在,编译器优先选择前两种方式。

  4. 哪些成员函数是特殊的成员函数?它们特殊的原因是什么?
    默认构造函数、默认复制构造函数、默认移动构造函数、默认析构函数、默认复制赋值运算符和默认移动赋值运算符。这些函数之所以特殊,是因为编译器将根据情况自动提供它们的默认版本。

  5. 假设 Fizzle 类只有如下所示的数据成员:

    class Fizzle {
    private:double bubbles[4000];
    ...
    };
    

    为什么不适合给这个类定义移动构造函数?要让这个类适合定义移动构造函数,应如何修改存储 4000 个 double 值的方式?

    答:在转让数据所有权(而不是复制数据)可行时,可使用移动构造函数,但对于标准数组,没有转让其所有权的机制。如果 Fizzle 使用指针和动态内存分配,则可将数据的地址赋给新指针,以转让其所有权。

  6. 修改下述简短的程序,使其使用 lambda 表达式而不是 f1()。请不要修改 show2()。

    #include <iostream>
    template <typename T>
    void show2(double x, T & fp) {std::cout << x << " -> " << fp(x) << '\n';
    }
    double f1(double x) {return 1.8 * x + 32;
    }
    int main() {show2(18.0, f1);return 0;
    }
    

    答:

    #include <iostream>
    template <typename T>
    void show2(double x, T & fp) {std::cout << x << " -> " << fp(x) << '\n';
    }
    int main() {show2(18.0, [](double x){return 1.8 * x + 32;} );return 0;
    }
    
  7. 修改下述简短而丑陋的程序,使其使用 lambda 表达式而不是函数符 Adder。请不要修改 sum()。

    #include<iostream>
    #include<array>
    const int Size = 5;
    template<typename T>
    void sum(std::array<double, Size> a, T& fp);class Adder {double tot;
    public:Adder(double q = 0) : tot(q) {}void operator() (double w) { tot += w; }double tot_v() const { return tot; }
    };int main() {double total = 0.0;Adder ad(total);std::array<double, Size> temp_c = {32.1, 34.3, 37.8, 35.2, 34.7 };sum(temp_c, ad);total = ad.tot_v();std::cout << "total: " << ad.tot_v() << '\n';return 0;
    }template<typename T>
    void sum(std::array<double, Size> a, T& fp) {for (auto pt = a.begin(); pt != a.end(); ++pt) {fp(*pt);}
    }
    

    答:

    #include<iostream>
    #include<array>
    const int Size = 5;
    template<typename T>
    void sum(std::array<double, Size> a, T& fp);int main() {double total = 0.0;std::array<double, Size> temp_c = {32.1, 34.3, 37.8, 35.2, 34.7 };sum(temp_c, [&total](double w) { total += w; });std::cout << "total: " << total << '\n';return 0;
    }template<typename T>
    void sum(std::array<double, Size> a, T& fp) {for (auto pt = a.begin(); pt != a.end(); ++pt) {fp(*pt);}
    }
    
http://www.lryc.cn/news/28299.html

相关文章:

  • YOLO-V5 系列算法和代码解析(八)—— 模型移植
  • js实现复制拷贝的兼容方法
  • 学习 Python 之 Pygame 开发魂斗罗(八)
  • Lesson11---分类问题
  • Python基础学习12——异常
  • [日常练习]练习17:链表头插法、尾插法练习
  • 第十四届蓝桥杯模拟赛(第三期)试题与题解 C++
  • 关于 “宏“
  • 1.2 CSS标签选择器,类选择器
  • 【Linux】进程等待 | 详解 wait/waitpid 的 status 参数
  • OpenAI眼中的无线调优策略
  • DataX入门
  • 第二章SpringBoot基础学习
  • B - Build Roads (最小生成树 + 打表)
  • k8s管理工具
  • Cannot start compiler The output path is not specified for module mystatic(已解决)
  • python入门应该怎么学习
  • 不懂命令, 如何将代码托管到Gitee上
  • Mysql常见面试题总结
  • python第一周作业
  • FLoyd算法的入门与应用
  • 303. 区域和检索 - 数组不可变
  • Spring Cloud融合Nacos配置加载优先级 | Spring Cloud 8
  • LeetCode 236.二叉树的最近公共祖先
  • awk简单实例(持续更新中)
  • react动态路由组件的封装
  • Vue项目中引入高德地图步骤详解
  • 软件测试用例篇(2)
  • leetcode题解-27. Remove Element
  • 【fly-iot飞凡物联】(4):在linux系统上搭建arduino环境,可以使用离线包,导入到arduino上即可。