C++Primer第五版 第十九章习题答案(21~26)

时间:2022-09-05 16:42:17

21、22、23:知识点1:union是一种特殊的类,可以包含多个数据成员,但是在任意时刻只能有一个数据成员可以有值,其他成员属于未定义的状态,分配给union的内存只要能存储它的最大数据成员即可

知识点2:union中不能含有引用类型的成员,但不可继承、不含有虚函数

知识点3:union的名字就相当于一个类型名,可以使用一对花括号显式初始化

union Token {};//后面的分号勿忘

Token first_elem = { ' a' };//初始化第一个成员

知识点4:匿名的union,没有名字,其中的成员可以直接访问,匿名union不能包含受保护成员和私有成员,也不能包含成员函数

知识点5:我们通常将含有类类型成员的union内嵌在另一个类之中,将其定义为匿名union,将自身类类型成员的控制权转移给该类

//Token.h  
#include <iostream>
#include <string>
#include <utility>
#include "Sales_data.h"
class Token//19.21
{
enum { INT, CHAR, DBL, STR, SALES/*19.22*/ }tok;
union {
char cval;
int ival;
double dval;
std::string sval;
Sales_data sdval;//19.22
};
void copyUnion(const Token &t) {
switch (t.tok) {
case INT: ival = t.ival;
break;
case CHAR:cval = t.cval;
break;
case DBL:dval = t.dval;
break;
case STR:new(&sval) std::string(t.sval);
break;
case SALES:new(&sdval) Sales_data(t.sdval);//19.22
break;
}
}
void moveUnion(Token &&t) {//19.23
switch (t.tok) {
case INT:
ival = std::move(t.ival);
break;
case CHAR:
cval = std::move(t.cval);
break;
case DBL:
dval = std::move(t.dval);
break;
case STR:
new(&sval) std::string(std::move(t.sval));
break;
case SALES:
new(&sdval) Sales_data(std::move(t.sdval));
break;
}
}
void free() {
if (tok == STR)
sval.std::string::~string();
if (tok == SALES)
sdval.~Sales_data();
}
public:
Token() :tok(INT), ival{ 0 } {};
Token(const Token &t) :tok(t.tok) { copyUnion(t); }
Token(Token &&t) :tok(std::move(t.tok)) {//19.23
moveUnion(std::move(t));
}
Token &operator=(Token &&t){//19.23
if(this != &t) {
free();
moveUnion(std::move(t));
tok = std::move(t.tok);
}
return *this;
}

Token &operator=(const Token &t) {
if (tok == STR&&t.tok != STR)sval.std::string::~string();
if (tok == SALES&&t.tok != SALES)sdval.~Sales_data();
if (tok == STR&&t.tok == STR)
sval = t.sval;
else if (tok == SALES&&t.tok == SALES)
sdval = t.sdval;
else
copyUnion(t);
tok = t.tok;
return *this;
}
~Token() {
if (tok == STR)
sval.std::string::~string();
if (tok == SALES)
sdval.~Sales_data();
}
Token &operator=(const std::string &s) {
free();
new(&sval) std::string(s);
tok = STR;
return *this;
}
Token &operator=(char c) {
free();
cval = c;
tok = CHAR;
return *this;
}
Token &operator=(int i) {
free();
ival = i;
tok = INT;
return *this;
}
Token &operator=(double d) {
free();
dval = d;
tok = DBL;
return *this;
}
Token &operator=(Sales_data &s) {
free();
new(&sdval) Sales_data(s);
tok = SALES;
return *this;
}
friend std::ostream &operator<<(std::ostream &os, const Token &t) {
switch (t.tok) {
case Token::INT: os << t.ival; break;
case Token::CHAR: os << t.cval; break;
case Token::DBL: os << t.dval; break;
case Token::STR: os << t.sval; break;
case Token::SALES: os << t.sdval; break;
}
return os;
}

};


//main.cpp  
#include <iostream>
#include <string>
#include "Token.h"
int main()
{
using namespace std;
string s = "string";
Sales_data item("c++ primer 5", 12, 128.0);
int i = 12;
char c = 'c';
double d = 1.28;
Token t;
t = i;
cout << t << "\t";
t = c;
cout << t << "\t";
t = d;
cout << t << "\t";
t = s;
cout << t << "\t";
t = item;
cout << t << endl;
Token t2 = t;
cout << t2 << "\t";
t2 = s;
cout << t2 << "\t";
t2 = t;
cout << t2 << "\t";
t2 = c;
cout << t2 << "\t";
t = s;
t2 = std::move(t);
cout << t2 << endl;
Token t3 = std::move(t2);
cout << t3 << "\t";
t3 = t3;
cout << t3 << "\t";
t3 = item;
cout << t3 << endl;
t2 = std::move(t3);
cout << t2 << endl;
system("pause");
return 0;
}


24:赋给自己时,每个成员都会调用自身类所拥有的赋值构造函数,没毛病~


25:见上main.cpp


26:知识点1:类可以定义在函数的内部,称之为局部类,并且必须是完整定义的,其中也不能包含静态成员

知识点2:定义在函数内部的类,不可以使用函数中的局部变量

知识点3:C++从C继承而来的两种不可移植的特性:位域和volatile

知识点4:当一个程序需要向其他程序或者硬件设备传递二进制数据时,通常会用到位域

知识点5:当对象的值可能在程序的控制或检测之外被改变时,应将对象声明为volatile,以此告诉编译器不应对这样的对象进行优化

知识点6:链接指示extern "C",指出任意非C++所用的语言,还可以使extern "Ada"等等,可以加单条语句或复合多条语句,还可以加入头文件

知识点7:C语言不支持重载,因此C链接提示只能说明重载函数中的一个


答案:见知识点7,不合法