7-1
#include<iostream>
struct Sales_data{
std::string bookNo;
unsigned units_sold=0;
double revenue=0.0;
};
int main(){
Sales_data total;
if(std::cin>>total.bookNo>>total.units_sold>>total.revenue){
Sales_data trans;
while(std::cin>>trans.bookNo>>trans.units_sold>>trans.revenue){
if(total.bookNo==trans.bookNo){
total.units_sold+=trans.units_sold;
total.revenue+=trans.revenue;
}else{
std::cout<<trans.bookNo<<" "<<trans.units_sold<<" "<<trans.revenue<<std::endl;
total=trans;
}
}
std::cout<<total.bookNo<<" "<<total.units_sold<<" "<<total.revenue<<std::endl;
}else{
std::cerr<<"No data~~"<<std::endl;
}
return 0;
}
7-2
#include<iostream>
class Sales_data{
std::string isbn() const {return bookNo;}
Sales_data& Sales_data::combine(const Sales_data &rhs){
units_sold+=rhs.units_sold;
revenue+=rhs.revenue;
return *this;
}
std::string bookNo;
unsigned units_sold=0;
double revenue=0.0;
};
int main(){
return 0;
}
7-3
#include<iostream>
class Sales_data{
public:
std::string isbn() const {return bookNo;}
Sales_data& Sales_data::combine(const Sales_data &rhs){
units_sold+=rhs.units_sold;
revenue+=rhs.revenue;
return *this;
}
std::string bookNo;
unsigned units_sold=0;
double revenue=0.0;
};
int main(){
Sales_data total;
if(std::cin>>total.bookNo>>total.units_sold>>total.revenue){
Sales_data trans;
while(std::cin>>trans.bookNo>>trans.units_sold>>trans.revenue){
if(total.isbn()==trans.isbn()){
total.combine(trans);
}else{
std::cout<<trans.bookNo<<" "<<trans.units_sold<<" "<<trans.revenue<<std::endl;
total=trans;
}
}
std::cout<<total.bookNo<<" "<<total.units_sold<<" "<<total.revenue<<std::endl;
}else{
std::cerr<<"No data~~"<<std::endl;
}
return 0;
}
7-4
#include<iostream>
class Person{
public:
std::string name;
std::string address;
};
int main(){
return 0;
}
7-5
#include<iostream>
class Person{
public:
std::string get_name() const {return name_;}
std::string get_address() const {return address_;}
private:
std::string name_;
std::string address_;
};
int main(){
return 0;
}
应该设置为const,这是由于在get_name和get_address两个函数体内不会改变this所指的对象,所以把this设置为指向常量的指针是有助于提高函数的灵活性。
7-6
7-7
7-8
由于read函数里面对item的的内容改变了。
而在print函数中,对item的内容没有改变。
7-9
#include<iostream>
class Person{
public:
std::string get_name() const {return name_;}
std::string get_address() const {return address_;}
std::string name_;
std::string address_;
};
std::istream &read(std::istream &is,Person &person){
is>>person.name_>>person.address_;
return is;
}
std::ostream &printf(std::ostream &os,const Person &person){
os<<person.get_name()<<" "<<person.get_address();
return os;
}
int main(){
return 0;
}
7-10
read函数返回值为istream对象。有两种情况会使一个istream对象的bool转型为false:读到EOF(文件结束标志)或遇到一个无效的值(输入流进入fail状态)。
7-11
#include<iostream>
class Sales_data{
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(p*n){}
Sales_data(std::istream &);
std::string isbn() const {return bookNo;}
Sales_data& Sales_data::combine(const Sales_data &rhs){
units_sold+=rhs.units_sold;
revenue+=rhs.revenue;
return *this;
}
std::string bookNo;
unsigned units_sold=0;
double revenue=0.0;
};
Sales_data::Sales_data(std::istream &is){
read(is,*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<<" ";
}
int main(){
Sales_data t1;
Sales_data t2("11-xxx-99");
Sales_data t3("11-xxx-99",10,100);
Sales_data t4(std::cin);
return 0;
}
7-12
#include<iostream>
class Sales_data{
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(p*n){}
Sales_data(std::istream &){read(is,*this);}
std::string isbn() const {return bookNo;}
Sales_data& Sales_data::combine(const Sales_data &rhs){
units_sold+=rhs.units_sold;
revenue+=rhs.revenue;
return *this;
}
std::string bookNo;
unsigned units_sold=0;
double revenue=0.0;
};
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<<" ";
}
int main(){
Sales_data t1;
Sales_data t2("11-xxx-99");
Sales_data t3("11-xxx-99",10,100);
Sales_data t4(std::cin);
return 0;
}
7-13
#include<iostream>
class Sales_data{
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(p*n){}
Sales_data(std::istream &is){read(is,*this);}
std::string isbn() const {return bookNo;}
Sales_data& Sales_data::combine(const Sales_data &rhs){
units_sold+=rhs.units_sold;
revenue+=rhs.revenue;
return *this;
}
std::string bookNo;
unsigned units_sold=0;
double revenue=0.0;
};
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<<" ";
}
int main(){
Sales_data total(std::cin);
if(total.isbn().empty()){
std::istream &is=std::cin;
while(is){
Sales_data trans(is);
if(trans.isbn()==total.isbn()){
total.combine(trans);
}else{
std::cout<<trans.bookNo<<" "<<trans.units_sold<<" "<<trans.revenue<<std::endl;
total=trans;
}
}
std::cout<<total.bookNo<<" "<<total.units_sold<<" "<<total.revenue<<std::endl;
}else{
std::cerr<<"No data~~"<<std::endl;
}
return 0;
}
7-15
#include<iostream>
class Person{
public:
Person(){}
Person(const std::string &s_name,const std::string &s_address):name_(s_name),address_(s_address){}
Person(std::istream &is);
std::string get_name() const {return name_;}
std::string get_address() const {return address_;}
std::string name_;
std::string address_;
};
Person::Person(std::istream &is){
read(is,*this);
}
std::istream &read(std::istream &is,Person &person){
is>>person.name_>>person.address_;
return is;
}
std::ostream &printf(std::ostream &os,const Person &person){
os<<person.get_name()<<" "<<person.get_address();
return os;
}
int main(){
return 0;
}
7-16
一个类可以包含0个或多个访问说明符,而且对于某个访问说明符能出现多少次也没有严格限定。每个访问说明符指定了接下来的成员的访问级别,其有效范围直到出现下一个访问说明符或者到达类的结尾为止。所以,对位置和次数没有限制。
7-17
使用struct关键字,则定义在第一个访问符之前的成员是public的。
使用class关键字,则这些成员是private的。
7-18
封装实现了类的接口和实现的分离,隐藏了类的实现细节,用户只能接触到类的接口。
7-19
将两个成员变量name和address声明为private,其他函数声明为public。
7-20
友元在其他类或者函数访问该类的非公有成员时有用。
优点:可以灵活地实现需要访问若干类的私有或受保护成员才能完成的任务,便于与其他不支持类的语言进行混合编程;通过使用友元函数重载可以更自然第使用C++语言的I/O流库。
缺点:一个类将对非公有成员的访问权授予其他的函数或类,会破坏该类的封装性,降低该类的可靠性和可维护性。
7-21
#include<iostream>
class Sales_data{
friend std::istream &read(std::istream &is,Sales_data &item);
friend std::ostream &print(std::ostream &os,const Sales_data &item);
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(p*n){}
Sales_data(std::istream &is){read(is,*this);}
std::string isbn() const {return bookNo;}
Sales_data& Sales_data::combine(const Sales_data &rhs){
units_sold+=rhs.units_sold;
revenue+=rhs.revenue;
return *this;
}
std::string get_bookNo(){return bookNo;}
unsigned get_units_sold(){return units_sold;}
double get_revenue(){return revenue;}
private:
std::string bookNo;
unsigned units_sold=0;
double revenue=0.0;
};
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<<" ";
}
int main(){
Sales_data total(std::cin);
if(total.isbn().empty()){
std::istream &is=std::cin;
while(is){
Sales_data trans(is);
if(trans.isbn()==total.isbn()){
total.combine(trans);
}else{
std::cout<<trans.get_bookNo()<<" "<<trans.get_units_sold()<<" "<<trans.get_revenue()<<std::endl;
total=trans;
}
}
std::cout<<total.get_bookNo()<<" "<<total.get_units_sold()<<" "<<total.get_revenue()<<std::endl;
}else{
std::cerr<<"No data~~"<<std::endl;
}
return 0;
}
7-22
#include<iostream>
class Person{
public:
Person(){}
Person(const std::string &s_name,const std::string &s_address):name_(s_name),address_(s_address){}
Person(std::istream &is);
std::string get_name() const {return name_;}
std::string get_address() const {return address_;}
private:
std::string name_;
std::string address_;
};
Person::Person(std::istream &is){
read(is,*this);
}
std::istream &read(std::istream &is,Person &person){
is>>person.name_>>person.address_;
return is;
}
std::ostream &printf(std::ostream &os,const Person &person){
os<<person.get_name()<<" "<<person.get_address();
return os;
}
int main(){
return 0;
}
7-23
7-24
#include<string>
class Screan{
public:
using pos=std::string::size_type;
Screan()=default;
Screan(pos ht,pos wd,int size):height(ht),width(wd),contents(size,' '){}
Screan(pos ht,pos wd,char c):height(ht),width(wd),contents(ht*wd,c){}
private:
pos cursor=0;
pos height=0,width=0;
std::string contents;
};
7-25
可以。
当类需要分配类对象之外的资源时,默认的拷贝和赋值操作讲不安全。但当使用vector或者string对象时,默认的拷贝和赋值操作可以正常工作。
7-26
7-27
#include<iostream>
#include<string>
class Screen{
public:
using pos=std::string::size_type;
Screen()=default;
Screen(pos ht,pos wd,int size):height(ht),width(wd),contents(size,' '){}
Screen(pos ht,pos wd,char c):height(ht),width(wd),contents(ht*wd,c){}
Screen &move(pos r,pos c);
Screen &set(char);
Screen &set(pos,pos,char);
Screen &display(std::ostream &os){do_display(os);return *this;}
const Screen &display(std::ostream &os) const {do_display(os);return *this;}
private:
pos cursor=0;
pos height=0,width=0;
std::string contents;
void do_display(std::ostream &os) const {os<<contents;}
};
inline Screen &Screen::move(pos r,pos c){
pos row=r*width;
cursor=row+c;
return *this;
}
inline Screen &Screen::set(char c){
contents[cursor]=c;
return *this;
}
inline Screen &Screen::set(pos r,pos col,char ch){
contents[r*width+col]=ch;
return *this;
}
int main(){
Screen myScreen(5,5,'X');
myScreen.move(4,0).set('#').display(std::cout);
std::cout<<std::endl;
myScreen.display(std::cout);
std::cout<<std::endl;
return 0;
}
输出数据:
XXXXXXXXXXXXXXXXXXXX#XXXX
XXXXXXXXXXXXXXXXXXXX#XXXX
7-28
如果返回类型是Screen,那么move返回的是 *this 的一个副本,因此set函数只能改变临时副本而不能改变myScreen的值。
7-29
#include<iostream>
#include<string>
class Screen{
public:
using pos=std::string::size_type;
Screen()=default;
Screen(pos ht,pos wd,int size):height(ht),width(wd),contents(size,' '){}
Screen(pos ht,pos wd,char c):height(ht),width(wd),contents(ht*wd,c){}
Screen move(pos r,pos c);
Screen set(char);
Screen set(pos,pos,char);
Screen display(std::ostream &os){do_display(os);return *this;}
const Screen display(std::ostream &os) const {do_display(os);return *this;}
private:
pos cursor=0;
pos height=0,width=0;
std::string contents;
void do_display(std::ostream &os) const {os<<contents;}
};
inline Screen Screen::move(pos r,pos c){
pos row=r*width;
cursor=row+c;
return *this;
}
inline Screen Screen::set(char c){
contents[cursor]=c;
return *this;
}
inline Screen Screen::set(pos r,pos col,char ch){
contents[r*width+col]=ch;
return *this;
}
int main(){
Screen myScreen(5,5,'X');
myScreen.move(4,0).set('#').display(std::cout);
std::cout<<std::endl;
myScreen.display(std::cout);
std::cout<<std::endl;
return 0;
}
输出数据:
XXXXXXXXXXXXXXXXXXXX#XXXX
XXXXXXXXXXXXXXXXXXXXXXXXX
可以发现,myScreen调用了move函数,但是并没有改变myScreen中成员变量的值。
7-30
优点:
- 程序的意图更明确
- 函数的参数可以与成员同名,如
void setAddr(const std::string &addr) { this->addr = addr; }
缺点:
- 有时候显得有点多余,如
std::string getAddr() const { return this->addr; }
7-31
class X;
class Y;
class X{
Y *y=nullptr;
};
class Y{
X x;
};
7-32
#include<string>
#include<vector>
using ScreenIndex=std::vector<Screen>::size_type;
class Window_mgr{
public:
void clear(ScreenIndex);
private:
std::vector<Screen> screens{Screen(24,80,' ')};
};
void Window_mgr::clear(ScreenIndex i){
Screen &s=screens[i];
s.contents=std::string(s.height*s.width,' ');
}
class Screen{
friend void Window_mgr::clear(ScreenIndex);
public:
using pos=std::string::size_type;
Screen()=default;
Screen(pos ht,pos wd,int size):height(ht),width(wd),contents(size,' '){}
Screen(pos ht,pos wd,char c):height(ht),width(wd),contents(ht*wd,c){}
Screen move(pos r,pos c);
Screen set(char);
Screen set(pos,pos,char);
Screen display(std::ostream &os){do_display(os);return *this;}
const Screen display(std::ostream &os) const {do_display(os);return *this;}
private:
pos cursor=0;
pos height=0,width=0;
std::string contents;
void do_display(std::ostream &os) const {os<<contents;}
};
inline Screen Screen::move(pos r,pos c){
pos row=r*width;
cursor=row+c;
return *this;
}
inline Screen Screen::set(char c){
contents[cursor]=c;
return *this;
}
inline Screen Screen::set(pos r,pos col,char ch){
contents[r*width+col]=ch;
return *this;
}
7-33