栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

《C++ Primer》第19章 19.6节习题答案

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

《C++ Primer》第19章 19.6节习题答案

《C++ Primer》第19章 特殊工具与技术

19.6节 union:一种节省空间的类习题答案

练习19.21:编写你自己的Token类。

【出题思路】

通过编写Token类,练习使用类对union成员进行管理控制。

【解答】

class Token {

public:
	// 因为union含有一个string成员,所以Token必须定义拷贝控制成员
	Token(): tok(INT), ival{0} { }
	Token(const Token &t): tok(t.tok) { copyUnion(t); }
	Token &operator=(const Token&);
	~Token() { if (tok == STR) sval.~string(); }
	Token &operator=(const std::string&);
	Token &operator=(char);
	Token &operator=(int);
	Token &operator=(double);
private:
    enum {INT, CHAR, DBL, STR} tok; // 判断式
    union {                         // 匿名联合 
        char   cval;
        int    ival;
        double dval;
		std::string sval;
    }; // 每个Token对象含有一个该未命名联合类型的未命名成员
	// 检查判别式,然后酌情拷贝union成员
	void copyUnion(const Token&);  
};

练习19.22:为你的Token类添加一个Sales_data类型的成员。

【出题思路】

练习在类中添加成员,其中包括对成员的管理判别式、赋新值、销毁等操作。

【解答】

#ifndef PROGRAM19_22_H
#define PROGRAM19_22_H


#include 
using std::string;

#include 

class Token {
friend std::ostream &operator<<(std::ostream&, const Token&);
public:
    // 因为union含有一个string成员,所以Token必须定义拷贝控制成员
    // 定义移动构造函数和移动赋值运算符的任务留待本节练习完成
    Token(): tok(INT), ival{0} { }
    Token(const Token &t): tok(t.tok) { copyUnion(t); }
    Token &operator=(const Token&);
    // 如果union含有一个Sales_data成员,则我们必须销毁它

    Token &operator=(Sales_data);
    Token &operator=(char);
    Token &operator=(int);
    Token &operator=(double);
private:
    enum {INT, CHAR, DBL, SDATA} tok; // 判断式
    union {                         // 匿名联合
        char   cval;
        int    ival;
        double dval;
        Sales_data sval;
    }; //每个Token对象含有一个该未命名联合类型的未命名成员
    // 检查判别式,然后酌情拷贝union成员
    void copyUnion(const Token&);
};

inline
void Token::copyUnion(const Token &t)
{
    switch (t.tok) {
        case Token::INT: ival = t.ival; break;
        case Token::CHAR: cval = t.cval; break;
        case Token::DBL: dval = t.dval; break;

        case Token::STR: new(&sval) Sales_data(t.sval); break;
    }
}

inline
std::ostream &operator<<(std::ostream &os, const Token &t)
{
    switch (t.tok) {
        case Token::INT: return os << t.ival;
        case Token::CHAR: return os << t.cval;
        case Token::DBL: return os << t.dval;
        case Token::STR: return os << t.sval;
    }
}

inline
Token &Token::operator=(double d)
{
    if (tok == STR) sval.~string();  // if we have a string, free it
    dval = d;
    tok = DBL;
    return *this;
}

inline
Token &Token::operator=(char c)
{
    //如果当前存储的是Sales_data,释放它
    if (tok == STR) sval.~Sales_data();
    cval = c;//为成员赋值
    tok = CHAR;//更新判别式
    return *this;
}

inline
Token &Token::operator=(int i)
{
    //如果当前存储的是Sales_data,释放它
    if (tok == STR) sval.~Sales_data();
    ival = i;                        // 为成员赋值
    tok = INT;                       // 更新判别式
    return *this;
}

inline
Token &Token::operator=(const Sales_data &s)
{
    //如果当前存储的是Sales_data,可以直接赋值
    if (tok == SDATA)
        sval = s;
    else
        new(&sval) Sales_data(s);  // 否则需要先构造一个Sales_data
    tok = SDATA;                 // 更新判别式
    return *this;
}

inline
Token &Token::operator=(const Token &t)
{
    //如果此对象的值是string而t的值不是,则我们必须释放原来的string
    if (tok == STR && t.tok != STR) sval.~Sales_data();
    if (tok == STR && t.tok == STR)
        sval = t.sval;//无须构造一个新string
    else
        copyUnion(t);//如果t.tok是STR,则需要构造一个
    tok = t.tok;
    return *this;
}

#endif // PROGRAM19_22_H

练习19.23:为你的Token类添加移动构造函数和移动赋值运算符。

【出题思路】

定义移动构造函数和移动赋值运算符。

【解答】

#include 
using std::string;

#include 

class Token {
friend std::ostream &operator<<(std::ostream&, const Token&);
public:
    // 因为union含有一个string成员,所以Token必须定义拷贝控制成员

    Token(): tok(INT), ival{0} { }
    Token(const Token &t): tok(t.tok) { copyUnion(t); }
    Token &operator=(const Token&);
    // 移动构造函数和移动赋值运算符
    Token(Token &&other);
    Token &operator=(Token &&other);
    //如果union含有一个Sales_data成员,则我们必须销毁它
    ~Token() { if(tok == SDATA) savl.~Sales_data(); }
    Token &operator=(Sales_data);
    Token &operator=(char);
    Token &operator=(int);
    Token &operator=(double);
private:
    enum {INT, CHAR, DBL, SDATA} tok; // 判断式
    union {                         // 匿名联合
        char   cval;
        int    ival;
        double dval;
        Sales_data sval;
    }; //每个Token对象含有一个该未命名联合类型的未命名成员
    // 检查判别式,然后酌情拷贝union成员
    void copyUnion(const Token&);
};

inline
void Token::copyUnion(const Token &t)
{
    switch (t.tok) {
        case Token::INT: ival = t.ival; break;
        case Token::CHAR: cval = t.cval; break;
        case Token::DBL: dval = t.dval; break;

        case Token::STR: new(&sval) Sales_data(t.sval); break;
    }
}

inline
std::ostream &operator<<(std::ostream &os, const Token &t)
{
    switch (t.tok) {
        case Token::INT: return os << t.ival;
        case Token::CHAR: return os << t.cval;
        case Token::DBL: return os << t.dval;
        case Token::STR: return os << t.sval;
    }
}

inline
Token &Token::operator=(double d)
{
    if (tok == STR) sval.~string();  // if we have a string, free it
    dval = d;
    tok = DBL;
    return *this;
}

inline
Token &Token::operator=(char c)
{
    //如果当前存储的是Sales_data,释放它
    if (tok == STR) sval.~Sales_data();
    cval = c;//为成员赋值
    tok = CHAR;//更新判别式
    return *this;
}

inline
Token &Token::operator=(int i)
{
    //如果当前存储的是Sales_data,释放它
    if (tok == STR) sval.~Sales_data();
    ival = i;                        // 为成员赋值
    tok = INT;                       // 更新判别式
    return *this;
}

inline
Token &Token::operator=(const Sales_data &s)
{
    //如果当前存储的是Sales_data,可以直接赋值
    if (tok == SDATA)
        sval = s;
    else
        new(&sval) Sales_data(s);  // 否则需要先构造一个Sales_data
    tok = SDATA;                 // 更新判别式
    return *this;
}

inline
Token &Token::operator=(const Token &t)
{
    //如果此对象的值是string而t的值不是,则我们必须释放原来的string
    if (tok == STR && t.tok != STR) sval.~Sales_data();
    if (tok == STR && t.tok == STR)
        sval = t.sval;//无须构造一个新string
    else
        copyUnion(t);//如果t.tok是STR,则需要构造一个
    tok = t.tok;
    return *this;
}

练习19.24:如果我们将一个Token对象赋给它自己将发生什么情况?

【出题思路】

熟悉理解移动赋值运算符的原理。

【解答】

因为在移动赋值运算符上添加了检测机制,当一个对象自己给自己赋值时,会先检测,避免不必要或者是灾难性的后果。

练习19.25:编写一系列赋值运算符,令其分别接受union中各种类型的值。

【出题思路】

熟悉理解赋值运算符的处理机制的原理。

【解答】

#ifndef PROGRAM19_25_H
#define PROGRAM19_25_H


#include 
using std::string;

#include 


class Token {
friend std::ostream &operator<<(std::ostream&, const Token&);
public:
    Token(): tok(INT), ival{0} { }
    Token(const Token &t): tok(t.tok) { copyUnion(t); }
    Token &operator=(const Token&);

    ~Token() { if (tok == STR) sval.~string(); }

    Token &operator=(const std::string&);
    Token &operator=(char);
    Token &operator=(int);
    Token &operator=(double);
private:
    enum {INT, CHAR, DBL, STR} tok;
    union {
        char   cval;
        int    ival;
        double dval;
        std::string sval;
    };

    void copyUnion(const Token&);
};

inline
void Token::copyUnion(const Token &t)
{
    switch (t.tok) {
        case Token::INT: ival = t.ival; break;
        case Token::CHAR: cval = t.cval; break;
        case Token::DBL: dval = t.dval; break;

        case Token::STR: new(&sval) std::string(t.sval); break;
    }
}

inline
std::ostream &operator<<(std::ostream &os, const Token &t)
{
    switch (t.tok) {
        case Token::INT: return os << t.ival;
        case Token::CHAR: return os << t.cval;
        case Token::DBL: return os << t.dval;
        case Token::STR: return os << t.sval;
    }
}

inline
Token &Token::operator=(double d)
{
    if (tok == STR) sval.~string();
    dval = d;
    tok = DBL;
    return *this;
}

inline
Token &Token::operator=(char c)
{
    if (tok == STR) sval.~string();
    cval = c;
    tok = CHAR;
    return *this;
}

inline
Token &Token::operator=(int i)
{
    if (tok == STR) sval.~string();
    ival = i;
    tok = INT;
    return *this;
}

inline
Token &Token::operator=(const std::string &s)
{
    if (tok == STR)
        sval = s;
    else
        new(&sval) std::string(s);
    tok = STR;
    return *this;
}

inline
Token &Token::operator=(const Token &t)
{

    if (tok == STR && t.tok != STR) sval.~string();
    if (tok == STR && t.tok == STR)
        sval = t.sval;
    else
        copyUnion(t);
    tok = t.tok;
    return *this;
}

#endif // PROGRAM19_25_H
#include "program19_25.h"

#include 
using std::string;

#include 
using std::cout;
using std::endl;

int main()
{
    Token token;
    Token t2;
    Token t3;
    cout << t2 << " " << t3 << endl;
    t2 = string("tim world!");
    t3 = "pineapple bye";
    token = t2;
    token = "cmale";
    cout << token << endl;
    t2 = t3;
    cout << t2 << endl;

    token = 58;
    cout << token << endl;
}

运行结果:

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/529151.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号