C++ Primer第七章习题

练习7.1

#include <iostream>
#include <string>

using namespace std;

struct Sales_data
{
	string bookNo;
	unsigned units_sold = 0;
	double revenue = 0;
};

int main(int argc, char* argv)
{
	Sales_data total;
	if (cin >> total.bookNo >> total.units_sold >> total.revenue)
	{
		Sales_data trans;
		while (cin >> trans.bookNo >> trans.units_sold >> trans.revenue)
		{
			if (total.bookNo == trans.bookNo)
			{
				total.units_sold += trans.units_sold;
				total.revenue += trans.revenue;
			}
			else
			{
				cout << total.bookNo << total.units_sold << total.revenue << endl;
				total.bookNo = trans.bookNo;
				total.units_sold = trans.units_sold;
				total.revenue = total.revenue;
			}
		}
		cout << total.bookNo << total.units_sold << total.revenue << endl;
	}
	else
	{
		cerr << "No data!" << endl;
		return -1;
	}
	return 0;
	
}

练习7.2

struct Sales_data
{
	string isbn() const { return bookNo; }
	Sales_data& combine(const Sales_data& trans);
	string bookNo;
	unsigned units_sold = 0;
	double revenue = 0;
};
Sales_data& Sales_data::combine(const Sales_data& trans)
{
	units_sold += trans.units_sold;
	revenue += trans.revenue;
	return *this;
}

练习7.3

int main(int argc, char* argv)
{
	Sales_data total;
	if (cin >> total.bookNo >> total.units_sold >> total.revenue)
	{
		Sales_data trans;
		while (cin >> trans.bookNo >> trans.units_sold >> trans.revenue)
		{
			if (total.isbn() == trans.isbn())
			{
				total.combine(trans);
			}
			else
			{
				cout << total.isbn() << total.units_sold << total.revenue << endl;
				total.bookNo = trans.isbn();
				total.units_sold = trans.units_sold;
				total.revenue = total.revenue;
			}
		}
		cout << total.isbn() << total.units_sold << total.revenue << endl;
	}
	else
	{
		cerr << "No data!" << endl;
		return -1;
	}
	return 0;

}

练习7.4

struct Person
{
	string name;
	string address;
};

练习7.5

struct Person
{
	string const getName() const { return name; }
	string const getAddr() const { return address; }
	string name;
	string address;

};

应该是const的,因为这些成员函数的作用只是读取调用它的对象的属性,不需要改变

练习7.6 7.7

#include <iostream>
#include <string>

using namespace std;

struct Sales_data
{
	string isbn() const { return bookNo; }
	Sales_data& combine(const Sales_data& trans);
	string bookNo;
	unsigned units_sold = 0;
	double revenue = 0;
};
Sales_data& Sales_data::combine(const Sales_data& trans)
{
	units_sold += trans.units_sold;
	revenue += trans.revenue;
	return *this;
}

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

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

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

int main(int argc, char* argv)
{
	Sales_data total;
	if (read(cin,total))
	{
		Sales_data trans;
		while (read(cin,trans))
		{
			if (total.isbn() == trans.isbn())
			{
				total.combine(trans);
			}
			else
			{
				print(cout, total);
				cout << endl;
				total.bookNo = trans.isbn();
				total.units_sold = trans.units_sold;
				total.revenue = trans.revenue;
			}
		}
		print(cout, total);
	}
	else
	{
		cerr << "No data!" << endl;
		return -1;
	}
	return 0;

}

习题7.8

read参数需要更改对象的属性,因而定义为普通引用;
print无需更改对象属性,定义为常量引用更好些。

习题7.9

#include <iostream>
#include <string>

using namespace std;

struct Person
{
	string const getName() const { return name; }
	string const getAddr() const { return address; }
	string name;
	string address;

};

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

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

int main()
{
	Person p1;
	read(cin, p1);
	print(cout,p1);
	return 0;

}

习题7.10

先将输入流中的输入写入data1,再将接下来的输入写入data2.因为is作为参数在函数内部并没有发生改变,read的返回值仍是cin。

习题7.11

#include <iostream>
#include <string>

using namespace std;
struct Sales_data;
istream& read(istream &,Sales_data &);
ostream& print(ostream &,Sales_data &);
struct Sales_data
{
    Sales_data() = default;
    Sales_data(const string &s):bookNo(s) {}
    Sales_data(const string &s, unsigned n, double p):bookNo(s),units_sold(n),revenue(n*p) {}
    Sales_data(std::istream &);
	string isbn() const { return bookNo; }
	Sales_data& combine(const Sales_data& trans);
	string bookNo;
	unsigned units_sold = 0;
	double revenue = 0;
};
Sales_data& Sales_data::combine(const Sales_data& trans)
{
	units_sold += trans.units_sold;
	revenue += trans.revenue;
	return *this;
}

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

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

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

int main(int argc, char** argv)
{
    Sales_data data1;
    Sales_data data2("KS990S");
    Sales_data data3("KSLLLL",3,10.3);
    read(cin,data1);
    print(cout,data1);
    print(cout,data2);
    print(cout,data3);
    return 0;
}

习题7.12


#include <iostream>
#include <string>

using namespace std;
struct Sales_data;
istream& read(istream &,Sales_data &);
ostream& print(ostream &,Sales_data &);

struct Sales_data
{
    Sales_data() = default;
    Sales_data(const string &s):bookNo(s) {}
    Sales_data(const string &s, unsigned n, double p):bookNo(s),units_sold(n),revenue(n*p) {}
    Sales_data(std::istream &is)
    {
        read(is,*this);
    }
	string isbn() const { return bookNo; }
	Sales_data& combine(const Sales_data& trans);
	string bookNo;
	unsigned units_sold = 0;
	double revenue = 0;
};

习题7.13

int main(int argc, char** argv)
{
	Sales_data total(cin);
	if (!total.isbn().empty())
	{
		Sales_data trans;
		while (read(cin,trans))
		{
			if (total.isbn() == trans.isbn())
			{
				total.combine(trans);
			}
			else
			{
				print(cout, total);
				cout << endl;
                total = trans;
			}
		}
		print(cout, total);
	}
	else
	{
		cerr << "No data!" << endl;
		return -1;
	}
	return 0;

}

练习7.15


#include <iostream>
#include <string>

using namespace std;
struct Person;
istream& read(istream&, Person&);
ostream& print(ostream&,const Person&);

struct Person
{
    Person() = default;
    Person(const string &nm, const string &addr):name(nm),address(addr) {}
    Person(istream &is) {read(is,*this);}
	string const getName() const { return name; }
	string const getAddr() const { return address; }
	string name;
	string address;

};

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

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

int main()
{
	Person p1("wfs","dcl"),p2(cin);
	print(cout,p1);
	print(cout,p2);
	return 0;

}

练习7.16

一个类可以包含0个或者多个说明符,对位置和次数都没有限定。public之后的成员在整个程序内都可以被访问,主要用来定义程序的接口;private只能被类的成员函数访问,但是不能被使用该类的代码访问。

练习7.17

有且仅有一个区别:默认访问权限不同

练习7.18

对类的使用者隐藏类的实现细节,这即为封装:可以强制使用者使用类的接口,提升类的标准性与鲁棒性。

练习7.19

理论上是要这样声明的

class Person
{
public:
    Person() = default;
    Person(const string &nm, const string &addr):name(nm),address(addr) {}
    Person(istream &is) {read(is,*this);}
	string const getName() const { return name; }
	string const getAddr() const { return address; }
private:
	string name;
	string address;

};

但是这样是无法编译通过的,因为read函数访问了私有成员。所以重写read/print函数。(其实可以声明为友元函数,下一节再说)

istream& read(istream &is, Person &person)
{
    string name,addr;
    is >> name >> addr;
    Person person_tmp(name,addr);
    person = person_tmp;
	return is;
}

ostream& print(ostream &os, const Person &person)
{
	os << person.getName() << ' ' << person.getAddr();
	return os;
}

练习7.20

友元是为了允许其他类和函数访问它的非公有成员
利:增加类的灵活性
弊:一定程度上破坏了类的封装性

练习7.21

class Sales_data
{
    friend istream& read(istream &,Sales_data &);
    friend ostream& print(ostream &,Sales_data &);
public:
    Sales_data() = default;
    Sales_data(const string &s):bookNo(s) {}
    Sales_data(const string &s, unsigned n, double p):bookNo(s),units_sold(n),revenue(n*p) {}
    Sales_data(std::istream &is)
    {
        read(is,*this);
    }
	string isbn() const { return bookNo; }
	Sales_data& combine(const Sales_data& trans);
private:
	string bookNo;
	unsigned units_sold = 0;
	double revenue = 0;
};

练习7.22

class Person
{
    friend istream& read(istream&, Person&);
    friend ostream& print(ostream&,const Person&);
public:
    Person() = default;
    Person(const string &nm, const string &addr):name(nm),address(addr) {}
    Person(istream &is) {read(is,*this);}
    string const getName() const { return name; }
    string const getAddr() const { return address; }
private:
    string name;
    string address;

};

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

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

练习7.23/24

class Screen
{
    public:
        using pos = string::size_type;
        Screen() = default;
        Screen(pos h, pos w):height(h),width(w),content(h*w,' ') {}
        Screen(pos h, pos w, char c):height(h),width(w),content(h*w,c) {}
        
    private:
        pos height,width;
        pos curse=0;
        string content;
};

练习7.25

能。Screen的资源都是在内置类型和string类型存储的,可以依赖于合成的版本。

练习7.27

#include <iostream>
#include <string>

using namespace std;

class Screen
{
    public:
        using pos = string::size_type;
        Screen() = default;
        Screen(pos h, pos w):height(h),width(w),content(h*w,' ') {}
        Screen(pos h, pos w, char c):height(h),width(w),content(h*w,c) {}
        char get() const
        {
            return content[curse];
        }
        inline char get(pos r, pos c) const ;
        Screen &move(pos r, pos c);
        Screen &set(pos r, pos c, char ch);
        Screen &set(char ch);
        const Screen &display(ostream& os) const
        {
            do_display(os);
            return *this;
        }

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

        
    private:
        void do_display(ostream &os) const
        {
            os << content;
        }
        pos height,width;
        pos curse=0;
        string content;
};

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

char Screen::get(pos r, pos c) const
{
    return content[r*width+c];
}

练习7.28/29

第一次的输出是(4,0)位置被设置为‘#’的screen内容,而第二次输出则是原始的screen内容。原因在于set与display的对象均为ie产生的副本,myScreen对象并未被set。

练习7.30

转载自https://blog.csdn.net/shamozhizhoutx/article/details/82291127
优点:
更明确,减少误读的可能性;
可以使用名称与成员名相同的形参。

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

缺点:
冗余代码增加。

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

练习7.31

#include <iostream>

using namespace std;
class X;
class Y;

class X
{
    Y* y;
};

class Y
{
    X x;
};

int main()
{
    X test_X;
    Y test_Y;
    return 0;
}

习题7.32

WIndow_mgr.h

#include <iostream>
#include <vector>
#include <string>
#include "Screen.h"

using namespace std;

class Window_mgr
{
    public:
        typedef vector<Screen>::size_type ScreenIndex;
        void clean(ScreenIndex i);


    private:
        vector<Screen> screens{Screen(24,24,' ')};
};

void Window_mgr::clean(ScreenIndex i)
{
    Screen &s = screens[i];
    s.content = string(s.height*s.width,' ');
}

Screen.h

#include <iostream>
#include <string>

using namespace std;

class Screen
{
    friend class Window_mgr;
    public:
        using pos = string::size_type;
        Screen() = default;
        Screen(pos h, pos w):height(h),width(w),content(h*w,' ') {}
        Screen(pos h, pos w, char c):height(h),width(w),content(h*w,c) {}
        char get() const
        {
            return content[curse];
        }
        inline char get(pos r, pos c) const ;
        Screen &move(pos r, pos c);
        Screen &set(pos r, pos c, char ch);
        Screen &set(char ch);
        const Screen &display(ostream& os) const
        {
            do_display(os);
            return *this;
        }

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

        
    private:
        void do_display(ostream &os) const
        {
            os << content;
        }
        pos height,width;
        pos curse=0;
        string content;
};

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

char Screen::get(pos r, pos c) const
{
    return content[r*width+c];
}

习题7.33

pos返回类型出现在类名之前,所以事实上他是在类的作用域之外的。

Screen::pos Screen::size() const
{
}

习题7.34

编译器只会考虑在使用别名之前出现的声明,故本题的改动会导致未声明的报错。

习题7.35

类的定义是对的。

如果成员使用了外层作用域中的名字,而该名字代表一种类型,则类不能在之后重新定义该名字。

但是本题的例子中类尚没有成员函数使用过外层作用域的名字,故可以重新定义。

成员函数setVal的定义是错的。因为setType的返回类型本应该是double(内层作用域的别名),但是因为在类外面定义函数时其返回类型Type在外层作用域,是string。

故应改为

Exercise::Type Exercise::setVal(Type parm)
{
}

习题7.36

rem比base更早初始化,所以用base去初始化rem是非法的。

习题7.38

Sales_data(istream &is = cin) { read(is, *this); }

习题7.39

非法。两个默认构造函数会导致非法重载。

习题7.58

有错误

静态数据成员必须在类的外部定义和初始化每个静态成员
然而,我们可以为静态成员提供const整数类型的类内初始值。不过要求静态成员必须是字面值常量类型的constexpr。

所以rate 和 vec的初始化必须在类外进行,而 vecSize 的初始化是正确的

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值