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

c++ primer 第14章 习题解答

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

c++ primer 第14章 习题解答

14.1节

14.1答

不同点:

重载操作符必须具有至少一个class或枚举类型的操作数。

重载操作符不保证操作数的求值顺序,例如对&&和| | 的重载版本不再具有“短路求值”的特征,两个操作数,两个操作数都要进行求值,而且不规定操作数的求值顺序。

相同点: 

        对于优先级和结合性及操作数的数目都不变。

14.2 答:

文件sales_data.cc

#include 
#include 
#include "Sales_data.h"
using namespace std;
Sales_data operator+(const Sales_data &lhs,const Sales_data &rhs)
{
Sales_data data = lhs;
data += rhs;
return data;
}

Sales_data& Sales_data::operator+=(const Sales_data &s)
{
	this->units_sold += s.units_sold;
	this->revenue += s.revenue;
	return *this;
}

istream & operator>>(istream &is,Sales_data &s)
{
is >> s.bookNo >> s.units_sold >> s.revenue;
	return is;
}
ostream & operator<<(ostream &os,const Sales_data &s)
{
os << s.bookNo << s.units_sold << s.revenue;
	return os;
}


文件  Sales_data.h 

class Sales_data {
	
	friend Sales_data operator+(const Sales_data &,const Sales_data &);
	friend istream & operator>>(istream &is,Sales_data &);
	friend ostream & operator<<(ostream &os,const Sales_data &);
	public:

	Sales_data &operator+=(const Sales_data &);

	std::string bookNo;
	unsigned units_sold = 0;
	double revenue = 0.0;
};

注意:切记不可在友元函数的前面加Sales_data::,否则编译器回提示,C++:‘std::ostream& String::operator<<(std::ostream&, const Sales_data &)’ must take exactly one argument

14.3

答:

(a)使用了c++内置版本的const char *版本的 ‘==’运算符。

字符串字面量是 const char* 类型

(b)string类型的"=="运算符

(c)vector类型的"=="运算符

(d)首先const char *类型的"stone"转换为 string,然后使用string类型的“=="

14.4

答:

(a)%通常定义为非成员,因为可以左右调换

(b)%=会改变自身状态,成员

(c)++成员

(d)->必须为成员

(e)&&非成员,一般不建议重载(&&和| |重载后,短路求值属性会失效)

(f)<<非成员,因为左操作数必须是 ostream类型。

(g)==  一般定义为非成员

(h)()必须为成员,否则编译器会报错。

赋值运算符,下标运算符,调用运算符,成员运算符必须是成员运算符,其余没有强制要求。

14.5

答:

我们以Date类为例,为其定义重载的输出运算符,输入运算符可参照实现,显然,为Date定义输入输出运算符,可以让我们像输入输出内置类型对象那样输入输出Date,在易用性和代码的可读性上有明显的好处。因此,定义这两个重载运算符是合理的。

文件date.h

#ifndef DATE_H
#define DATE_H

#include 
#include 
using namespace std;
class Date
{
	public:
		Date(){}
		Date(int y,int m,int d){year = y;month = m;day = d;}
		friend ostream & operator<< (ostream &os,const Date &dt);
	private:
		int year,month,day;
};

#endif
#include 
#include 
#include "date.h"
using namespace std;
ostream & operator<<(ostream & os,const Date &dt)
{
    const char sep = 't';
    os << "year:"<< dt.year << sep << "month:"<< dt.month< 

14.2节

14.2.1习题

习题14.6

14.7

 

#ifndef STRING_H
#define STRING_H

#include 
#include 
#include 
#include 
#include 
#include 
#include 

class String {
friend String operator+(const String&, const String&);
friend String add(const String&, const String&);
friend std::ostream &print(std::ostream&, const String&);
friend std::ostream &operator<<(ostream &os,const String &);
public:
	String() = default;

	// cp points to a null terminated array, 
	// allocate new memory & copy the array
	String(const char *cp) : 
	          sz(std::strlen(cp)), p(a.allocate(sz))
	          { std::uninitialized_copy(cp, cp + sz, p); }

	// copy constructor: allocate a new copy of the characters in s
	String(const String &s):sz(s.sz), p(a.allocate(s.sz))
	          { std::uninitialized_copy(s.p, s.p + sz , p); }

	// move constructor: copy the pointer, not the characters, 
	// no memory allocation or deallocation
	String(String &&s) noexcept : sz(s.size()), p(s.p) 
	          { s.p = 0; s.sz = 0; }

	String(size_t n, char c) : sz(n), p(a.allocate(n))
	          { std::uninitialized_fill_n(p, sz, c); }

	// allocates a new copy of the data in the right-hand operand; 
	// deletes the memory used by the left-hand operand
	String &operator=(const String &);
	// moves pointers from right- to left-hand operand
	String &operator=(String &&) noexcept;

	// unconditionally delete the memory because each String has its own memory
	~String() noexcept { if (p) a.deallocate(p, sz); }

	// additional assignment operators
	String &operator=(const char*);         // car = "Studebaker"
	String &operator=(char);                // model = 'T'
	String &
	operator=(std::initializer_list); // car = {'a', '4'}
	
	const char *begin()                         { return p; }
	const char *begin() const                   { return p; }
	const char *end()                      { return p + sz; }
	const char *end() const                { return p + sz; }

	size_t size() const                        { return sz; }
	void swap(String &s)
	                { auto tmp = p; p = s.p; s.p = tmp; 
	                  auto cnt = sz; sz = s.sz; s.sz = cnt; }
private:
	std::size_t sz = 0;
	char *p = nullptr;
	static std::allocator a;
};
String make_plural(size_t ctr, const String &, const String &);
inline
void swap(String &s1, String &s2)
{
	s1.swap(s2);
}

#endif
 

#include 
using std::strlen;

#include 
using std::copy; 

#include 
using std::size_t; 

#include 
using std::ostream; 

#include 
using std::swap;

#include 
using std::initializer_list;

#include 
using std::uninitialized_copy;

#include "string.h"

// define the static allocator member
std::allocator String::a;

// copy-assignment operator
String & String::operator=(const String &rhs)
{
	// copying the right-hand operand before deleting the left handles self-assignment
    auto newp = a.allocate(rhs.sz); // copy the underlying string from rhs
	uninitialized_copy(rhs.p, rhs.p + rhs.sz, newp);

	if (p)
		a.deallocate(p, sz); // free the memory used by the left-hand operand
	p = newp;    // p now points to the newly allocated string
	sz = rhs.sz; // update the size

    return *this;     
}

// move assignment operator
String & String::operator=(String &&rhs) noexcept
{
	// explicit check for self-assignment
	if (this != &rhs) {
		if (p)
			a.deallocate(p, sz);  // do the work of the destructor
		p = rhs.p;    // take over the old memory
		sz = rhs.sz;
		rhs.p = 0;    // deleting rhs.p is safe
		rhs.sz = 0;
	}
    return *this; 
}

String& String::operator=(const char *cp)
{
	if (p) a.deallocate(p, sz);
	p = a.allocate(sz = strlen(cp));
	uninitialized_copy(cp, cp + sz, p);
	return *this;
}

String& String::operator=(char c)
{
	if(p) a.deallocate(p, sz);
	p = a.allocate(sz = 1);
	*p = c;
	return *this;
}

String& String::operator=(initializer_list il)
{
	// no need to check for self-assignment
	if (p)
		a.deallocate(p, sz);        // do the work of the destructor
	p = a.allocate(sz = il.size()); // do the work of the copy constructor
	uninitialized_copy(il.begin(), il.end(), p);
	return *this;
}
// named functions for operators
ostream &print(ostream &os, const String &s)
{
	auto p = s.begin();
	while (p != s.end())
		os << *p++ ;
	return os;
}

String add(const String &lhs, const String &rhs) 
{
	String ret;
	ret.sz = rhs.size() + lhs.size();   // size of the combined String
	ret.p = String::a.allocate(ret.sz); // allocate new space
	uninitialized_copy(lhs.begin(), lhs.end(), ret.p); // copy the operands
	uninitialized_copy(rhs.begin(), rhs.end(), ret.p + lhs.sz);
	return ret;  // return a copy of the newly created String
}
	
// return plural version of word if ctr isn't 1
String make_plural(size_t ctr, const String &word,
                               const String &ending)
{
        return (ctr != 1) ?  add(word, ending) : word;
}



// chapter 14 will explain overloaded operators
ostream & operator<<(ostream &os,const String &s)
{
for(auto ptr = s.begin(); ptr != s.end(); ++ptr)
	os << *ptr << std::endl;  //or can be written: print(os,s)

return os;
}




String operator+(const String &lhs, const String &rhs) 
{
	return add(lhs, rhs);
}



int main()
{



	return 0;
}

14.8 同练习14.5

14.2.2重载输入运算符

istream & operator>>(istream &is,Sales_data &s)
{
double price;
is >> s.bookNo >> s.units_sold >> price;
if(is)
	s.revenue = price * s.units_sold;
else
	s = Sales_data(); //input failure,object is set to the default state
	return is;
}
输入运算符定义注意事项如下: 1.输入后要判断流是否正确,如果正确继续执行往后的操作 2.如果错误,那么把被输入的对象置为默认状态。

 

 

 

 习题14.2.2

习题14.9

istream & operator>>(istream &is,Sales_data &s)
{
double price;
is >> s.bookNo >> s.units_sold >> price;
if(is)
	s.revenue = price * s.units_sold;
else
	s = Sales_data(); //input failure,object is set to the default state
	return is;
}
ostream & operator<<(ostream &os,const Sales_data &s)
{
os << s.bookNo << s.units_sold << s.revenue;
	return os;
}

提示:输入运算符必须在输入后立刻判断流的状态,如果流失败(说明读取数据发生错误),那么立刻把被输入的对象置于默认的状态。

14.10

(a)参数中传入的Sales_data 对象将会得到输入的值,其中BookNo、units_sold、price的值分别是:0-201-99999-9、10、24.95,同时,revenue的值是249.5。

(b)输入错误,参数中传入的Sales_data对象会得到默认值。

练习14.11

对于上题中的(a)程序将会正常执行,对于(b)程序将会发生错误,bookNo得到值10,units_sold得到值24,price得到值0.95,最后revenue得到值revenue = 24 * 0.95。

练习14.12

#include "date.h"
#include 
#include 
using namespace std;
istream & operator>>(istream &,Date &);
ostream & operator<<(ostream &,const Date &);
int main()
{
Date d;
cin >> d;
cout << d << endl;

	return 0;
}
#ifndef DATE_H_INCLUDE
#define DATE_H_INCLUDE 

#include 
#include 
using namespace std;

class Date
{
	public:
	Date(){}
	Date(int y,int m,int d){year = y; month = m; day = d;}
	friend istream & operator>>(istream &is,Date &dt)
		{
			is >> dt.year >> dt.month >> dt.day;
			if(!is)
				{
					dt = Date(0,0,0);				
				}				
			return is;
		}
	friend ostream & operator<<(ostream &os,const Date& dt)
		{
		os << dt.year << dt.month << dt.day;


			return os;
		}
	private:
	int year,month,day;

};


#endif

习题14.17

bool operator==(const Date &lhs,const Date &rhs)
{
	return lhs.year == rhs.year && lhs.month == rhs.month && lhs.day == rhs.day;
}

bool operator!=(const Date &lhs,const Date &rhs)
{
	return !(lhs == rhs);
}

判断几个条件是否同时成立,可以使用 && 把这几个条件连起来。秒。

14.3.2节

练习14.18

       对于Sales_data的==运算符来说,如果两笔交易的revenue和units_sold成员不同,那么即时他们的ISBN相同也无济于事,他们仍然是不相同的。如果我们定义的<运算符仅仅比较ISBN成员,那么将发生这样的情况:两个ISBN相同但是revenue和units_sold不同的对象经比较是不想等的,但是其中的任何一个都不小于另一个。然而实际情况是,如果我们有两个对象并且一个都不比另一个小,则从道理上来说这两个对象应该是相等的。

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

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

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