《C++ Primer Plus》第18章:探讨 C++ 新标准(8)
-
使用大括号括起的初始化列表语法重写下述代码。重写后的代码不应使用数组 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 };
-
在下述简短的程序中,哪些函数调用不对?为什么?对于合法的函数调用,指出其引用参数指向的是什么。
#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) 的临时返回值。
-
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 左值可与左值或右值形参匹配,但如果与前两种方式同时存在,编译器优先选择前两种方式。
-
哪些成员函数是特殊的成员函数?它们特殊的原因是什么?
默认构造函数、默认复制构造函数、默认移动构造函数、默认析构函数、默认复制赋值运算符和默认移动赋值运算符。这些函数之所以特殊,是因为编译器将根据情况自动提供它们的默认版本。 -
假设 Fizzle 类只有如下所示的数据成员:
class Fizzle { private:double bubbles[4000]; ... };
为什么不适合给这个类定义移动构造函数?要让这个类适合定义移动构造函数,应如何修改存储 4000 个 double 值的方式?
答:在转让数据所有权(而不是复制数据)可行时,可使用移动构造函数,但对于标准数组,没有转让其所有权的机制。如果 Fizzle 使用指针和动态内存分配,则可将数据的地址赋给新指针,以转让其所有权。
-
修改下述简短的程序,使其使用 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; }
-
修改下述简短而丑陋的程序,使其使用 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);} }