C++ Primer 第五版第七章习题答案

书籍版本:2019年9月第一版;王刚 杨巨峰译;电子工业出版社

编译器 : win10  && VS2015

7.1

CSales_data头文件

#pragma once
#include <string>
using namespace std;

class CSales_data
{
public:
	CSales_data();
	~CSales_data();

	unsigned isbn();

	void combine(CSales_data cs);

	bool read();

	void print();

private:
	string bookNo;
	unsigned units_sold ;
	double revenue;
};

CSales_data源文件

#include "stdafx.h"
#include "Sales_data.h"
#include <iostream>
#include <string>
using namespace std;

CSales_data::CSales_data()
{
	bookNo = "";
	units_sold = 0;
	revenue = 0.0;
}


CSales_data::~CSales_data()
{
}

unsigned CSales_data::isbn()
{
	return units_sold;
}

bool CSales_data::read()
{
	if (!(cin >> bookNo) )
	{
		return false;
	}
	if (!(cin >> units_sold))
	{
		return false;
	}
	if (!(cin >> revenue ))
	{
		return false;
	}
	return true;
}

void CSales_data::combine(CSales_data cs)
{
	bookNo += cs.bookNo;
	units_sold += cs.units_sold;
	revenue += cs.revenue;
}

void CSales_data::print()
{
	cout << bookNo << endl;
	cout << units_sold << endl;
	cout << revenue << endl;
}

主函数

#include "stdafx.h"
#include <iostream>
#include <vector>
#include <string>
#include "Sales_data.h"
using namespace std;


int main(int argc, char *argv[])
{
	CSales_data total;
	if(total.read())
	{
		CSales_data trans;
		if (trans.read())
		{
			if (total.isbn() == trans.isbn())
			{
				total.combine(trans);
			}
			else
			{
				total.print();
			}
		}
	}

	system("pause");
}

7.2

如上题。

7.3

如7.1

7.4

#include "stdafx.h"
#include <iostream>
#include <vector>
#include <string>
#include "Sales_data.h"
using namespace std;


int main(int argc, char *argv[])
{
	CSales_data total;
	if(total.read())
	{
		CSales_data trans;
		if (trans.read())
		{
			if (total.isbn() == trans.isbn())
			{
				total.combine(trans);
			}
			else
			{
				total.print();
			}
		}
	}

	system("pause");
}

7.5

#pragma once

#include <string>
using namespace std;

class CPerson
{
public:
	CPerson();
	~CPerson();

	string GetName() const
	{
		return m_strName;
	}

	string GetAdd() const
	{
		return m_strAdd;
	}

private:
	string m_strName;
	string m_strAdd;

};

7.6

#pragma once
#include <string>
using namespace std;

class CSales_data
{
public:
	CSales_data();
	~CSales_data();

	unsigned isbn();

	void combine(CSales_data cs);

	bool read();

	void print();

	int avg_price();

public:
	string bookNo;
	unsigned units_sold ;
	double revenue;
};

istream &read(istream &is, CSales_data &item)
{
	double price = 0;
	is >> item.bookNo >> item.units_sold >> price;
	item.revenue = price*item.units_sold;
	return is;
}
ostream &print(ostream &os, CSales_data &item)
{
	os << item.isbn() << " " << item.units_sold << " " << item.revenue << " " << item.avg_price();
	return os;
}
CSales_data add(const CSales_data &lhs, const CSales_data &rhs)
{
	CSales_data sum = lhs;
	sum.combine(rhs);
	return sum;
}

7.7

看前几题

7.8

read会对参数的成员变量的值进行修改;print不会改值只取值;

7.9

7.10

连续输入两个CSales_data对象

7.11

CSales_data::CSales_data()
{
	bookNo = "";
	units_sold = 0;
	revenue = 0.0;
}

7.12

在.h文件中添加

CSales_data(istream is);

7.13

    Sales_data total(cin);
	if (cin)
	{
		Sales_data trans(cin);
		do
		{
			if (total.isbn() == trans.isbn())
				total.combine(trans);
			else
			{
				print(cout, total) << endl;
				total = trans;
			}
		}while (read(cin, trans));
		print(cout, total)<<endl;
	}
	else
	{
		cerr << "No data?!"<<endl;
	}

7.14

CSales_data::CSales_data(string bNo, unsigned uSold, double rev)
	: bookNo(bNo), units_sold(uSold), revenue(rev)
{
}

7.15

7.11与7.14的答案都可以

7.16

访问说明符出现的位置和次数没有限定。

对于我们愿意让整个程序都可以访问的成员,应该定义成public。

对于我们只想让自己这个类单独使用的成员,定义为private。

7.17

使用class那么在我们定义第一个访问说明符之前的所有成员默认都是private的,struct则都默认为public的。

7.18

封装是为了将被封装的部分对外隐藏。

封装的优点:书中page242

①确保用户代码不会无意间破坏封装对象的状态;

②被封装的类的具体实现可以随时改变,而无需调整用户级别的代码;

7.19

我的person类中所有的成员变量都是private的,所有的成员函数都是public的;但是只是这个person的函数都要被外界调用才将其都定义为public,当不想要被外界知道或是看见时(例如那些成员变量)就应将其定义为private。

7.20

在需要允许其他类或函数访问他的私有成员时,可将其生命为友元。

友元声明只能出现在类定义的内部,但是在类内出现的具体位置不限。其不受访问控制级别的约束。(不是类内成员)

友元的声明仅仅指定了其访问的权限,并非通常意义上的函数声明。故友元声明之外还需专门对函数进行一次声明。

缺点是会破坏了原有类的封装性。

7.21

将变量声明为private即可。

7.22

同上一题。

7.23

头文件:

#pragma once

#include <iostream>
using namespace std;

class CScreen
{
public:
	typedef std::string::size_type pos;

public:
	CScreen();// 默认构造函数
	CScreen(pos ht, pos wd, char c) ;
	~CScreen();

public:
	char get() const
	{
		return contents[cursor];
	}
	inline char get(pos ht, pos wd) const;
	CScreen& move(pos r, pos c);

private:
	pos cursor;
	pos height;
	pos width;
	std::string contents;
};

源文件:

#include "stdafx.h"
#include "Screen.h"

CScreen::CScreen()
{
	height = 0;
	width = 0;
	cursor = 0;
}

CScreen::CScreen(pos ht, pos wd, char c) : height(ht), width(wd), contents(ht * wd, c)
{
}

CScreen::~CScreen()
{
}

CScreen& CScreen::move(pos r, pos c)
{
	pos row = r * width;
	cursor = row + c;
	return *this;
}

char CScreen::get(pos r, pos c) const
{
	pos row = r * width;
	return contents[row + c];
}

7.24

#include "stdafx.h"
#include "Screen.h"

CScreen::CScreen()
{
	height = 0;
	width = 0;
	cursor = 0;
}

CScreen::CScreen(pos ht, pos wd) :height(ht), width(wd), contents(ht * wd, ' ')
{
}

CScreen::CScreen(pos ht, pos wd, char c) : height(ht), width(wd), contents(ht * wd, c)
{
}

CScreen::~CScreen()
{
}

CScreen& CScreen::move(pos r, pos c)
{
	pos row = r * width;
	cursor = row + c;
	return *this;
}

char CScreen::get(pos r, pos c) const
{
	pos row = r * width;
	return contents[row + c];
}

7.25

能,因为Screen里的成员变量都是内置类型。

7.26

①将avg_price 的声明与定义都写在头文件中,这种为隐式声明的内联。

②在头文件中的avg_price声明前加inline,这种为显示声明。

7.27

头文件:

#pragma once

#include <iostream>
using namespace std;

class CScreen
{
public:
	typedef std::string::size_type pos;

public:
	CScreen();// 默认构造函数
	CScreen(pos ht, pos wd, char c);
	CScreen(pos ht, pos wd);
	~CScreen();

public:
	char get() const
	{
		return contents[cursor];
	}
	inline char get(pos ht, pos wd) const;
	CScreen& move(pos r, pos c);

	CScreen& set(char ch);
	CScreen& set(pos r, pos c, char ch);

	CScreen& display(std::ostream& os)
	{
		do_display(os);
		return *this;
	}
	const CScreen& display(std::ostream& os) const
	{
		do_display(os);
		return *this;
	}

private:
	void do_display(std::ostream& os) const
	{
		os << contents;
	}

private:
	pos cursor;
	pos height;
	pos width;
	std::string contents;
};

源文件:

#include "stdafx.h"
#include "Screen.h"

CScreen::CScreen()
{
	height = 0;
	width = 0;
	cursor = 0;
}

CScreen::CScreen(pos ht, pos wd) :height(ht), width(wd), contents(ht * wd, ' ')
{
}

CScreen::CScreen(pos ht, pos wd, char c) : height(ht), width(wd), contents(ht * wd, c)
{
}

CScreen::~CScreen()
{
}

CScreen& CScreen::move(pos r, pos c)
{
	pos row = r * width;
	cursor = row + c;
	return *this;
}

char CScreen::get(pos r, pos c) const
{
	pos row = r * width;
	return contents[row + c];
}

CScreen & CScreen::set(char ch)
{
	// TODO: 在此处插入 return 语句
	contents[cursor] = ch;
	return *this;
}

CScreen & CScreen::set(pos r, pos c, char ch)
{
	// TODO: 在此处插入 return 语句
	contents[r * width + c] = ch;
	return *this;
}

7.28

返回引用时意味着这些函数的返回的是对象本身。如果只是Screen类型的返回值,则那这些函数只返回一个临时副本,不会改变myScreen的值。

7.29

把函数返回值的&去掉即可。

7.30

优点:非常明确地指出访问的是对象的成员,并且,可以在成员函数中使用与数据成员同名的形参;

缺点:多余。

7.31

X类:

#pragma once

#include <string>
using namespace std;
class YClasss;

class XClass
{
public:
	XClass();
	~XClass();

private:
    YClass* m_y;

};

Y类:

#pragma once

#include <string>
#include "XClass.h"
using namespace std;


class YClass
{
public:
	YClass();
	~YClass();

private:
    XClass m_x;

};

7.32

Window_mgr头文件:

#pragma once

#include <vector>
#include "Screen.h"
using namespace std;
class CScreen;

class CWindow_mgr
{
public:
	CWindow_mgr();
	~CWindow_mgr();

	using ScreenIndex = std::vector<CScreen>::size_type;

	void clear(ScreenIndex si);

private:
	vector<CScreen> screens;
};

Window_mg源文件:

#include "stdafx.h"
#include "Screen.h"
#include "Window_mgr.h"


CWindow_mgr::CWindow_mgr()
{
	screens = { CScreen(24, 80, ' ') };
}


CWindow_mgr::~CWindow_mgr()
{
}

void CWindow_mgr::clear(ScreenIndex si)
{

}

Screen头文件

#pragma once

#include <iostream>
#include <string>
#include "Window_mgr.h"
using namespace std;

class CScreen
{
public:
	typedef std::string::size_type pos;

public:
	CScreen();// 默认构造函数
	CScreen(pos ht, pos wd, char c);
	CScreen(pos ht, pos wd);
	~CScreen();

public:
	char get() const
	{
		return contents[cursor];
	}
	inline char get(pos ht, pos wd) const;
	CScreen& move(pos r, pos c);

	CScreen& set(char ch);
	CScreen& set(pos r, pos c, char ch);

	CScreen& display(std::ostream& os)
	{
		do_display();
		return *this;
	}
	const CScreen& display(std::ostream& os) const
	{
		do_display();
		return *this;
	}

private:
	void do_display() const
	{
		cout<<contents;
	}

private:
	pos cursor;
	pos height;
	pos width;
	string contents;

	friend void CWindow_mgr::clear(ScreenIndex si);
};

7.33

会在.cpp文件中报错:未定义的标识符pos

改为

CScreen::pos CScreen::size() const
{
	return height * width;
}

7.34

编译器会报错,因为我们在pos声明之前就使用了它。

7.35

setvalue函数会报错,因为返回值Type是个string类型,但实际return的是int。

7.36

因为成员的初始化顺序与他们在类定义中的出现顺序一致;所以先初始化的应该是rem,但是rem初始化需要用到base的值,而此时base还没有初始化,所以会出错。

7.37

Sales_data next;    // 使用的是无参数的构造函数,其中的成员值都是默认值;

Sales_data last("9-999-99999-9");    // 使用的是参数为string的构造函数,其bookNo= 9-999-99999-9

7.38

CSales_data( std::istream &is = std::cin ) { is >> *this; }

7.39

不合法,都使用默认实参时编译器无法分辨该调用哪个构造函数。

7.40

Book(string author, int price, string publish, Data pubTime) : m_author(author), m_price(price), m_publish(publish), m_pubTime(pubTime){};

author为作者,price为价格, publish为出版社,pubTime为出版时间

7.41

	// 委托构造函数
	CSales_data(string bNo):CSales_data(bNo, 0, 0) {};
	CSales_data(unsigned uSold):CSales_data(" ", uSold, 0) {};
	CSales_data(string bNo, unsigned uSold):CSales_data(bNo, uSold, 0) {};
	CSales_data(unsigned uSold, double rev):CSales_data(" ", uSold, rev) {};

执行顺序是先执行被委托的函数(本题中即为有三个参数的构造函数),执行结束后再执行委托函数

7.42

// 被委托函数

Book(string author, int price, string publish, Data pubTime) : m_author(author), m_price(price), m_publish(publish), m_pubTime(pubTime){};

// 委托函数

Book(string author) : Book(author, 0, "", time){};

7.43

CClass(NoDefault nd) : m_noDefault(nd)
{
}

7.44

不合法,NoDefault类没有默认构造函数,不能默认初始化。编译器报错。

7.45

合法,因为我们为C定义了默认的构造函数。

7.46

a.  不正确,没有构造函数时编译器会添加一个默认的构造函数,但编译器添加的默认构造函数有时会有问题。

b   不正确,默认构造函数是对象在被默认初始化时执行的构造函数。

c   不正确,如果一个类没有默认构造函数,则当编译器确实需要隐式地使用默认构造函数时,该类无法使用。所以不论什么情况下,都应为类构建一个默认构造函数。

d   不正确,对于编译器合成的默认构造函数来说,对象类型的成员会执行各自的默认构造函数,内置类型和复合类型的成员只对定义在全局作用域的对象执行初始化。

7.47

是否将构造函数设置为explicit应根据我们的使用情况而定,如果我们愿意让使用者通过编译器隐式的把string对象转换为一个Sales_data对象,那么就无需设置为explicit;反之则需添加explicit。

不将构造函数设置为explicit可能会在有些时候使用较为方便,但有时也可能造成对string的使用与初衷不一致。

7.48

不是explicit时:

string null_isbn( "9-999-9999-9" );    //定义一个string对象

Sales_data item1( null_isbn );    //调用接受一个string的Sales_data的构造函数创建一个Sales_data对象

Sales_data item2( "9-999-9999-9");  //和上面的一样

是explicit时:

结果与不是explicit时一致,因为最多只进行了一步转换,即将"9-999-9999-9"转换为string,而之后创建Sales_data 是根据构造函数创建,并未再次使用类型转换。

7.49

a.   编译器会根据s隐式地调用Sales_data的构造函数,生成一个临时的Sales_data对象,然后传递给combine

b.   编译器报错error: invalid initialization of non-const reference of type 'Sales_data&' from an rvalue of type 'Sales_data',string可以转为一个临时的Sales_data对象,但不能转化为Sales_data类型的引用。

c.   error: assignment of member 'Sales_data::units_sold' in read-only object,声明最后的const会禁止函数对值做出改变,这个错误与参数无关。

7.50

只接受一个参数的构造函数最好设置为explicit

7.51

引用一份别人的回答:

Such as a function like that:

int getSize(const std::vector<int>&);

if vector has not defined its single-argument constructor as explicit. we can use the function like:

getSize(34);

What is this mean?
It's very confused.

But the std::string is different. In ordinary, we use std::string to replace const char *(the C language). so when we call a function like that:

void setYourName(std::string); // declaration.
setYourName("pezy"); // just fine.
it is very natural.

7.52

聚合类的定义:

①所有成员都是public

②没有定义任何构造函数

③没有类内初始值

④没有基类,也没有virtual函数

那么题中是想以将Sales_data看做聚合类来初始化他,但是64页的Sales_data写了默认值,不能当做聚合类

7.53

class Debug
{
public:
    constexpr Debug(bool b = true) : hw(b), io(b), other(b) { }
    constexpr Debug(bool h, bool i, bool o) : hw(h), io(i), other(o) {}
    constexpr bool any() { return hw || io || other; }
    void set_hw (bool b) { hw = b; }
    void set_io (bool b) { io = b; }
    void set_other (bool b) { other = b; }
private:
    bool hw;        // 硬件错误
    bool io;        // io错误
    bool other;     // 其它错误
};

7.54

不可以,因为这些set函数都没有return语句。

7.55

不是,它没有constexpr类型的构造函数,并且其成员不一定是字面值类型。

7.56

与类本身直接相关的而不是与类的各个对象保持关联的成员可以作为静态成员。静态成员属于所属的类,即所有由这个类产生的对象公用一个静态成员。

7.57

class Account
{
public:
    void calculate() { amount += amount * interestRate; }
    static double rate() { return interestRate; }
    static void rate(double);
private:
    string owner;
    double amount;
    static double interestRate;
    static double initRate();
};

7.58

    static double rate = 6.5;   // 错误:带有类内初始值设定项的成员必须为常量

    static const int vecSize = 20;

   static vector<double> vec(vecSize);  //错误:成员vecSize不是类型名;

应改为

static const double rete = 6.5;

static vector<double> vec;

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值