C++ Primer第五版_第七章习题答案(21~30)

文章目录

      • 练习7.21
      • 练习7.22
      • 练习7.23
      • 练习7.24
      • 练习7.25
      • 练习7.26
      • 练习7.27
      • 练习7.28
      • 练习7.29
      • 练习7.30

练习7.21

修改你的Sales_data 类使其隐藏实现的细节。你之前编写的关于Sales_data操作的程序应该继续使用,借助类的新定义重新编译该程序,确保其正常工作。

#ifndef CP5_ex7_21_h
#define CP5_ex7_21_h

#include 
#include 

class Sales_data
{
	friend std::istream &read(std::istream &is, Sales_data &item);
	friend std::ostream &print(std::ostream &os, const Sales_data &item);
	friend Sales_data add(const Sales_data &lhs, const Sales_data &rhs);

public:
	Sales_data() = default;
	Sales_data(const std::string &s) :bookNo(s) {}
	Sales_data(const std::string &s, unsigned n, double p) :bookNo(s), units_sold(n), revenue(n*p) {}
	Sales_data(std::istream &is) { read(is, *this); }

	std::string isbn() const { return bookNo; };
	Sales_data& combine(const Sales_data&);

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

Sales_data& Sales_data::combine(const Sales_data& rhs)
{
	units_sold += rhs.units_sold;
	revenue += rhs.revenue;
	return *this;
}

std::istream &read(std::istream &is, Sales_data &item)
{
	double price = 0;
	is >> item.bookNo >> item.units_sold >> price;
	item.revenue = price * item.units_sold;
	return is;
}

std::ostream &print(std::ostream &os, const Sales_data &item)
{
	os << item.isbn() << " " << item.units_sold << " " << item.revenue;
	return os;
}

Sales_data add(const Sales_data &lhs, const Sales_data &rhs)
{
	Sales_data sum = lhs;
	sum.combine(rhs);
	return sum;
}

#endif

练习7.22

修改你的Person 类使其隐藏实现的细节。

#ifndef CP5_ex7_22_h
#define CP5_ex7_22_h

#include 
#include 

struct Person
{
	friend std::istream &read(std::istream &is, Person &person);
	friend std::ostream &print(std::ostream &os, const Person &person);

public:
	Person() = default;
	Person(const std::string sname, const std::string saddr) :name(sname), address(saddr) {}
	Person(std::istream &is) { read(is, *this); }

	std::string getName() const { return name; }
	std::string getAddress() const { return address; }
private:
	std::string name;
	std::string address;
};

std::istream &read(std::istream &is, Person &person)
{
	is >> person.name >> person.address;
	return is;
}

std::ostream &print(std::ostream &os, const Person &person)
{
	os << person.name << " " << person.address;
	return os;
}

#endif

练习7.23

编写你自己的Screen 类型。

#ifndef CP5_ex7_23_h
#define CP5_ex7_23_h
#include 

class Screen
{
public:
	using pos = std::string::size_type;

	Screen() = default;
	Screen(pos ht, pos wd, char c) :height(ht), width(wd), contents(ht*wd, c)
	{}

	char get() const { return contents[cursor]; }
	char get(pos r, pos c) const { return contents[r*width + c]; }

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

#endif

练习7.24

给你的Screen 类添加三个构造函数:一个默认构造函数;另一个构造函数接受宽和高的值,然后将contents 初始化成给定数量的空白;第三个构造函数接受宽和高的值以及一个字符,该字符作为初始化后屏幕的内容。

#ifndef CP5_ex7_24_h
#define CP5_ex7_24_h
#include 

class Screen
{
public:
	using pos = std::string::size_type;

	Screen() = default;
	Screen(pos ht, pos wd) :height(ht), width(wd), contents(ht*wd, ' ') {}
	Screen(pos ht, pos wd, char c) :height(ht), width(wd), contents(ht*wd, c) {}

	char get() const { return contents[cursor]; }
	char get(pos r, pos c) const { return contents[r*width + c]; }

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

#endif

练习7.25

Screen 能安全地依赖于拷贝和赋值操作的默认版本吗?如果能,为什么?如果不能?为什么?

能。Screen 的成员只有内置类型和 string,因此能安全地依赖于拷贝和赋值操作的默认版本。管理动态内存的类则不能依赖于拷贝和赋值操作的默认版本,而且也应该尽量使用string 和 vector 来避免动态管理内存的复杂性。

练习7.26

将Sales_data::avg_price 定义成内联函数。

#ifndef CP5_ex7_26_h
#define CP5_ex7_26_h

#include 
#include 

class Sales_data
{
	friend std::istream &read(std::istream &is, Sales_data &item);
	friend std::ostream &print(std::ostream &os, const Sales_data &item);
	friend Sales_data add(const Sales_data &lhs, const Sales_data &rhs);

public:
	Sales_data() = default;
	Sales_data(const std::string &s) :bookNo(s) {}
	Sales_data(const std::string &s, unsigned n, double p) :bookNo(s), units_sold(n), revenue(n*p) {}
	Sales_data(std::istream &is) { read(is, *this); }

	std::string isbn() const { return bookNo; };
	Sales_data& combine(const Sales_data&);

private:
	inline double avg_price() const;

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

inline
double Sales_data::avg_price() const
{
	return units_sold ? revenue / units_sold : 0;
}

std::istream &read(std::istream &is, Sales_data &item);
std::ostream &print(std::ostream &os, const Sales_data &item);
Sales_data add(const Sales_data &lhs, const Sales_data &rhs);

#endif

练习7.27

给你自己的Screen 类添加move、set 和display 函数,通过执行下面的代码检验你的类是否正确。

Screen myScreen(5, 5, 'X');
myScreen.move(4, 0).set('#').display(cout);
cout << "\n";
myScreen.display(cout);
cout << "\n";
#ifndef CP5_ex7_27_h
#define CP5_ex7_27_h

#include 
#include 

class Screen
{
public:
	using pos = std::string::size_type;

	Screen() = default; // 1
	Screen(pos ht, pos wd) :height(ht), width(wd), contents(ht*wd, ' ') {} // 2
	Screen(pos ht, pos wd, char c) :height(ht), width(wd), contents(ht*wd, c) {} // 3

	char get() const { return contents[cursor]; }
	char get(pos r, pos c) const { return contents[r*width + c]; }
	inline Screen& move(pos r, pos c);
	inline Screen& set(char c);
	inline Screen& set(pos r, pos c, char ch);

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

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

private:
	pos cursor = 0;
	pos height = 0, width = 0;
	std::string contents;
};

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

inline Screen& Screen::set(char c)
{
	contents[cursor] = c;
	return *this;
}

inline Screen& Screen::set(pos r, pos c, char ch)
{
	contents[r*width + c] = ch;
	return *this;
}

#endif

练习7.28

如果move、set和display函数的返回类型不是Screen& 而是Screen,则在上一个练习中将会发生什么?

如果返回类型是Screen,那么move返回的是 *this 的一个副本,因此set函数只能改变临时副本而不能改变myScreen的值。

练习7.29

修改你的Screen 类,令move、set和display函数返回Screen并检查程序的运行结果,在上一个练习中你的推测正确吗?

推测正确。

练习7.30

通过this指针使用成员的做法虽然合法,但是有点多余。讨论显示使用指针访问成员的优缺点。

优点

  • 程序的意图更明确

  • 函数的参数可以与成员同名,如

      void setAddr(const std::string &addr) { this->addr = addr; }
    

缺点

  • 有时候显得有点多余,如

      std::string getAddr() const { return this->addr; }
    

你可能感兴趣的:(C++《i+1》,c++,开发语言,java)