《C++primer》v5 第7章 类 读书笔记 习题答案
7.1、7.2、7.3
#include<iostream>
#include<cstdio>
#include<vector>
#include<string>
using namespace std;
struct Sales_data
{
string bookNo;//isbn编号
unsigned units_sold=;//该书的销量
double revenue=0.0;//该书的总销售收入
string isbn()const {return bookNo;}
Sales_data& combine(const Sales_data &rhs)
{
units_sold+=rhs.units_sold;
revenue+=rhs.revenue;
return *this;
}
double avg_price() const
{
if(units_sold)
return revenue/units_sold;
else
;
}
};
Sales_data add(const Sales_data& lhs,const Sales_data& rhs)
{
Sales_data sum=lhs;
sum.combine(rhs);
return sum;
}
istream &read(istream &is,Sales_data &item)
{
;
is>>item.bookNo>>item.units_sold>>price;
item.revenue=item.units_sold*price;
return is;
}
ostream &print(ostream &os,const Sales_data &item)
{
os<<item.isbn()<<" "<<item.units_sold<<" "<<item.revenue<<" "<<item.avg_price();
return os;
}
int main()
{
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)<<endl;
total=trans;
}
}
print(cout,total)<<endl;
}
else
cerr<<"No data?"<<endl;
;
}
7.4
struct Person
{
string name,address;
};
7.5
当然应该是const。首先这些成员函数并不修改成员变量,其次为了方便常量调用,所以可以设为const。
struct Person
{
string name,address;
string getName()const
{
return name;
}
string getAddress() const
{
return address;
}
};
7.6、7.7略
7.8
因为read需要写到该变量中,需要修改该对象的值。print函数不需要改值。
7.9
struct Person
{
string name,address;
string getName()const
{
return name;
}
string getAddress() const
{
return address;
}
};
istream &read(istream &is,Person &per)
{
is>>per.name>>per.address;
return is;
}
ostream &print(ostream &os,const Person &per)
{
os<<per.getName()<<" "<<per.getAddress();
return os;
}
int main()
{
Person p;
while(read(cin,p))
print(cout,p)<<endl;
;
}
7.10
成功读取到数据
7.11
#include<iostream>
#include<cstdio>
#include<vector>
#include<string>
using namespace std;
struct Sales_data
{
string bookNo;//isbn编号
unsigned units_sold=;//该书的销量
double revenue=0.0;//该书的总销售收入
Sales_data(),revenue(){}
string isbn()const {return bookNo;}
Sales_data& combine(const Sales_data &rhs)
{
units_sold+=rhs.units_sold;
revenue+=rhs.revenue;
return *this;
}
double avg_price() const
{
if(units_sold)
return revenue/units_sold;
else
;
}
};
Sales_data add(const Sales_data& lhs,const Sales_data& rhs)
{
Sales_data sum=lhs;
sum.combine(rhs);
return sum;
}
istream &read(istream &is,Sales_data &item)
{
;
is>>item.bookNo>>item.units_sold>>price;
item.revenue=item.units_sold*price;
return is;
}
ostream &print(ostream &os,const Sales_data &item)
{
os<<item.isbn()<<" "<<item.units_sold<<" "<<item.revenue<<" "<<item.avg_price();
return os;
}
int main()
{
string s;
cin>>s;
Sales_data total(s);
print(cout,total)<<endl;
;
}
7.12
这里由于是在类内所以需要提前声明函数,而函数里又有该类,所以需要提前声明该类。
struct Sales_data;
istream &read(istream&,Sales_data&);
struct Sales_data
{
string bookNo;//isbn编号
unsigned units_sold=;//该书的销量
double revenue=0.0;//该书的总销售收入
Sales_data(),revenue(){}
Sales_data(istream &is)
{
read(is,*this);
}
string isbn()const {return bookNo;}
Sales_data& combine(const Sales_data &rhs)
{
units_sold+=rhs.units_sold;
revenue+=rhs.revenue;
return *this;
}
double avg_price() const
{
if(units_sold)
return revenue/units_sold;
else
;
}
};
Sales_data add(const Sales_data& lhs,const Sales_data& rhs)
{
Sales_data sum=lhs;
sum.combine(rhs);
return sum;
}
istream &read(istream &is,Sales_data &item)
{
;
is>>item.bookNo>>item.units_sold>>price;
item.revenue=item.units_sold*price;
return is;
}
ostream &print(ostream &os,const Sales_data &item)
{
os<<item.isbn()<<" "<<item.units_sold<<" "<<item.revenue<<" "<<item.avg_price();
return os;
}
int main()
{
Sales_data total(cin);
print(cout,total)<<endl;
;
}
7.13
略
7.14
如果没有初始化某个成员,那么它将用类内初始值初始化。
#include<iostream>
#include<cstdio>
#include<vector>
#include<string>
using namespace std;
struct Sales_data;
istream &read(istream&,Sales_data&);
struct Sales_data
{
string bookNo;//isbn编号
unsigned units_sold=;//该书的销量
double revenue=10.0;//该书的总销售收入
Sales_data() {}
Sales_data(),revenue() {}
Sales_data(istream &is)
{
read(is,*this);
}
string isbn()const
{
return bookNo;
}
Sales_data& combine(const Sales_data &rhs)
{
units_sold+=rhs.units_sold;
revenue+=rhs.revenue;
return *this;
}
double avg_price() const
{
if(units_sold)
return revenue/units_sold;
else
;
}
};
Sales_data add(const Sales_data& lhs,const Sales_data& rhs)
{
Sales_data sum=lhs;
sum.combine(rhs);
return sum;
}
istream &read(istream &is,Sales_data &item)
{
;
is>>item.bookNo>>item.units_sold>>price;
item.revenue=item.units_sold*price;
return is;
}
ostream &print(ostream &os,const Sales_data &item)
{
os<<item.isbn()<<" "<<item.units_sold<<" "<<item.revenue<<" "<<item.avg_price();
return os;
}
int main()
{
Sales_data total;
print(cout,total)<<endl;
;
}
7.15
struct Person
{
string name,address;
Person(string &_name,string &_address):name(_name),address(_address){}
string getName()const
{
return name;
}
string getAddress() const
{
return address;
}
};
7.16
在类外允许访问的成员应该在public后面
只允许在类内访问的成员应该在private后面
7.17
struct默认访问权限和继承方式是public
class默认访问权限和继承方式是private
7.18
封装:隐藏对象的属性和实现细节,仅对外开放接口,控制程序中的属性读取和修改的访问级别。
增强安全性和简化编程。
7.19
成员变量name、address应该声明为private,构造函数,getName,getAddress应该声明为public。
7.20
有些类或者函数需要访问该类的非公有成员,可以声明为友元。
好处是实现了访问类内非公有成员
坏处破坏了封装性
7.21
#include<iostream>
#include<cstdio>
#include<vector>
#include<string>
using namespace std;
class Sales_data;
istream &read(istream&,Sales_data&);
ostream &print(ostream&,const Sales_data&);
class Sales_data
{
friend istream &read(istream&,Sales_data&);
friend ostream &print(ostream&,const Sales_data&);
//friend Sales_data add(const Sales_data&,const Sales_data&);
private:
string bookNo;//isbn编号
unsigned units_sold=;//该书的销量
double revenue=10.0;//该书的总销售收入
public:
Sales_data() {}
Sales_data(),revenue() {}
Sales_data(istream &is)
{
read(is,*this);
}
string isbn()const
{
return bookNo;
}
Sales_data& combine(const Sales_data &rhs)
{
units_sold+=rhs.units_sold;
revenue+=rhs.revenue;
return *this;
}
double avg_price() const
{
if(units_sold)
return revenue/units_sold;
else
;
}
};
Sales_data add(const Sales_data& lhs,const Sales_data& rhs)
{
Sales_data sum=lhs;
sum.combine(rhs);
return sum;
}
istream &read(istream &is,Sales_data &item)
{
;
is>>item.bookNo>>item.units_sold>>price;
item.revenue=item.units_sold*price;
return is;
}
ostream &print(ostream &os,const Sales_data &item)
{
os<<item.isbn()<<" "<<item.units_sold<<" "<<item.revenue<<" "<<item.avg_price();
return os;
}
int main()
{
Sales_data total;
print(cout,total)<<endl;
;
}
7.22
class Person
{
private:
string name,address;
public:
Person(string &_name,string &_address):name(_name),address(_address) {}
string getName()const
{
return name;
}
string getAddress() const
{
return address;
}
};
7.23
#include<iostream>
#include<cstdio>
#include<vector>
#include<string>
using namespace std;
class Screen
{
public:
typedef std::string::size_type pos;
Screen()=default;
Screen(pos ht,pos wd,char c):height(ht),width(wd),contents(ht*wd,c){}
char get() const
{
return contents[cursor];
}
inline char get(pos ht,pos wd) const;
Screen &move(pos r,pos c);
private:
pos cursor=;
pos height=,width=;
string contents;
};
inline Screen &Screen::move(pos r,pos c)
{
pos row=r*width;
cursor=row+c;
return *this;
}
char Screen::get(pos r,pos c) const
{
return contents[r*width+c];
}
7.24
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){}
7.25
能。没有涉及一些指针类的操作。
7.26
inline double avg_price() const
{
if(units_sold)
return revenue/units_sold;
else
;
}
7.27
using namespace std;
class Screen
{
public:
typedef std::string::size_type pos;
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];
}
inline char get(pos ht,pos wd) const;
Screen &move(pos r,pos c);
Screen &set(char c)
{
contents[cursor]=c;
return *this;
}
Screen& display(ostream &os)
{
os<<height<<" "<<width<<" "<<contents;
return *this;
}
private:
pos cursor=;
pos height=,width=;
string contents;
};
inline Screen &Screen::move(pos r,pos c)
{
pos row=r*width;
cursor=row+c;
return *this;
}
char Screen::get(pos r,pos c) const
{
return contents[r*width+c];
}
int main()
{
Screen myScreen(,,'X');
myScreen.move(,).set('#').display(cout);
cout<<endl;
myScreen.display(cout);
cout<<endl;
;
}
输出:
XXXXXXXXXXXXXXXXXXXX#XXXX XXXXXXXXXXXXXXXXXXXX#XXXX
7.28
修改之后的输出:
XXXXXXXXXXXXXXXXXXXX#XXXX XXXXXXXXXXXXXXXXXXXXXXXXX
第一次输出时候的仅仅是原对象的一个副本,不是原来的对象。
所以第二次输出原来的对象,没有改变过。
7.29
略
7.30
如果有局部变量与成员变量同名会隐藏了该成员变量,所以可以通过this指针显式使用,其他情况下用this与不用都是一样的。
7.31
using namespace std;
class X;
class Y;
class X
{
Y *py;
};
class Y
{
X x;
};
声明之后,定义之前,该类是一种不完全类型。不完全类型只能定义指针或引用。
7.32
这个题有点难。
难在程序代码的组织。
第一步声明Screen。因为下面在定义Windows_mgr中,需要用到Screen类,注意没有用到Screen的成员。
第二步定义Windows_mgr同时声明clear但是不能定义clear,因为clear用到了Screen的成员,而此时Screen还未定义。
第三步定义Screen包括对于clear的友元声明,此时clear的声明已经存在
第四步定义clear,此时它才可以使用Screen的成员。
using namespace std;
class Screen;
class Window_mgr
{
public:
using ScreenIndex=std::vector<Screen>::size_type;
void clear(ScreenIndex);
private:
std::vector<Screen> screens ;
};
class Screen
{
// friend class Window_mgr;
friend void Window_mgr::clear(ScreenIndex );
public:
typedef std::string::size_type pos;
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];
}
inline char get(pos ht,pos wd) const;
Screen &move(pos r,pos c);
Screen &set(char c)
{
contents[cursor]=c;
return *this;
}
Screen& display(ostream &os)
{
os<<height<<" "<<width<<" "<<contents;
return *this;
}
private:
pos cursor=;
pos height=,width=;
string contents;
};
inline Screen &Screen::move(pos r,pos c)
{
pos row=r*width;
cursor=row+c;
return *this;
}
char Screen::get(pos r,pos c) const
{
return contents[r*width+c];
}
void Window_mgr::clear(ScreenIndex i)
{
Screen &s=screens[i];
s.contents=string(s.height*s.width,' ');
}
以前写代码都是声明的同时定义,感觉声明了以后隔好远才定义都是自己找麻烦。。这次算是有了新的体会。有时候必须提前声明但是无法定义,必须按一定顺序组织代码。
一个非常重要的地方,声明一个类,在后面定义之前只能用这个类名,而不能使用它的成员,因为编译器不知道它的成员都有谁。
7.33
遇到一个编译器无法识别pos,因为pos它不在类的作用域内。
正确写法:
Screen::pos Screen::size() const
{
return height*width;
}
7.34
编译错误,pos未定义。
7-35
编译错误。
首先一个错误是在定义setVal的地方,返回值这里的Type是全局的,即string,与类内声明不符,因此会编译错误。
正确写法:Exercise::Type Exercise::setVal(Type parm)
这样返回值就是double。
但是这个代码还是不能通过编译,因为initVal没有定义。由于在函数体内已经进入了类的作用域,所以这里调用的是类的initVal。
下面是我修改以后的代码。
#include<iostream>
#include<cstdio>
#include<vector>
#include<string>
using namespace std;
typedef int Type;
Type initVal()
{
cout<<"use func!"<<endl;
}
class Exercise
{
public:
typedef double Type;
Type setVal(Type);
Type initVal()
{
cout<<"use class!"<<endl;
}
private:
int val;
};
Exercise::Type Exercise::setVal(Type parm)
{
//val=parm+::initVal();//这样写就可以调用全局的initVal,注意我把全局的Type换成了int,因为string无法与double相加
val=parm+initVal();//这样写就可以调用类的initVal
return val;
}
int main()
{
Exercise e;
e.setVal(1.5);
;
}
7.36
struct X
{
X(int i,int j):base(i),rem(base%j) {}
int rem,base;
};
int main()
{
X x(,);
cout<<x.base<<" "<<x.rem<<endl;
;
}
成员变量初始化的顺序是与定义时的顺序一致的,因此上面先初始化rem(此时base是未定义的)再初始化base。所以最后结果是违背设计初衷的。
7.37
两个都调用了Sales_data(string s=""):bookNo(s){}
第一个bookNo="",units_sold=0,revenue=0.0.第一个是默认实参初始化,后两个是类内初始值
第二个bookNo="9-999-99999-9",unit_sold=0,revenue=0.0,第一个是直接初始化,后两个是类内初始值
7.38
Sales_data(istream &is=cin)
{
read(is,*this);
}
但此时不能在显式定义无参构造函数,因为两者会产生二义性调用。
7.39
不合法。二义性调用。
7.40
略
7.41
#include<iostream>
#include<cstdio>
#include<vector>
#include<string>
using namespace std;
class Sales_data;
istream &read(istream&,Sales_data&);
ostream &print(ostream&,const Sales_data&);
class Sales_data
{
friend istream &read(istream&,Sales_data&);
friend ostream &print(ostream&,const Sales_data&);
//friend Sales_data add(const Sales_data&,const Sales_data&);
private:
string bookNo;//isbn编号
unsigned units_sold=;//该书的销量
double revenue=10.0;//该书的总销售收入
public:
Sales_data():Sales_data(,)
{
cout<<"我是无参构造函数!"<<endl;
}
Sales_data(const string &s,unsigned cnt,double price):bookNo(s),units_sold(cnt),revenue(cnt*price)
{
cout<<"我是三参构造函数!"<<endl;
}
Sales_data(,)
{
cout<<"我是一参构造函数!"<<endl;
}
Sales_data(istream &is):Sales_data()
{
cout<<"我是istream构造函数!"<<endl;
read(is,*this);
}
string isbn()const
{
return bookNo;
}
Sales_data& combine(const Sales_data &rhs)
{
units_sold+=rhs.units_sold;
revenue+=rhs.revenue;
return *this;
}
double avg_price() const
{
if(units_sold)
return revenue/units_sold;
else
;
}
};
Sales_data add(const Sales_data& lhs,const Sales_data& rhs)
{
Sales_data sum=lhs;
sum.combine(rhs);
return sum;
}
istream &read(istream &is,Sales_data &item)
{
;
is>>item.bookNo>>item.units_sold>>price;
item.revenue=item.units_sold*price;
return is;
}
ostream &print(ostream &os,const Sales_data &item)
{
os<<item.isbn()<<" "<<item.units_sold<<" "<<item.revenue<<" "<<item.avg_price();
return os;
}
int main()
{
Sales_data a;
Sales_data b(");
Sales_data c(cin);
;
}
先执行委托的构造函数。
7.42
略
7.43
以下代码是不能通过编译的。因为C的默认构造函数会调用一个无参的Nodefault的构造函数,而它是不存在的。
using namespace std;
class Nodefault
{
public:
Nodefault(int x) {}
};
class C
{
private:
Nodefault nd;
public:
C()=default;
};
int main()
{
C c;
;
}
7.44
编译错误,缺少Nodefault的无参构造函数。
7.45
不合法,缺少Nodefault的无参构造函数。
7.46
(a)是的
(b)不是。也可能是有参数但是还有默认实参的构造函数。
(c)不对。默认构造函数是编译器自己合成的。即使该类没有成员变量,它依旧会被提供。
(d)是的。
7.47
可以吧?
7.48
如果只有Sales_data(const string &s);这一个函数的话,似乎不受影响。
7.49
(a)string隐式转化成Sales_data,要求该构造函数Sales_data(const string &s)不是explicit的
(b)无法通过编译。不懂?因为临时变量不能被绑定到普通引用上?
(c)string隐式转化成Sales_data&,要求该构造函数Sales_data(const string &s)不是explicit的
7.50
似乎都可以
7.51
string s="sfds"这样是合法的
但是vector<int> vec=10;这样缺少违背了设计初衷的。
7.52
这样初始化方法只有聚合类才支持。
而64页的该类由于提供了类内初始值因此不是聚合类。
正确写法
using namespace std;
struct Sales_data
{
string bookNo;//isbn编号
unsigned units_sold;//该书的销量
double revenue;//该书的总销售收入
};
int main()
{
Sales_data total={,34.567};
;
}
7.53
略
7.54
不能。constexpr 的成员函数是隐身const,不能修改成员变量。
7.55
没有constexpr 构造函数?
7.56
所有类的对象共享的成员称为类的静态成员。
普通成员,类的每个对象独占一份。
7.57
略
7.58
不能在类内初始化静态成员,const静态成员除外。
正确写法
class Example
{
public:
static double rate;
;
static vector<double> vec;
};
;
vector<double> Example::vec(vecSize);
《C++primer》v5 第7章 类 读书笔记 习题答案的更多相关文章
- 《C++primer》v5 第1章 开始 读书笔记 习题答案
从今天开始在博客里写C++primer的文字.主要以后面的习题作业为主,会有必要的知识点补充. 本人也是菜鸟,可能有不对之处,还望指出. 前期内容可能会比较水. 1.1略 1.2略 1.3 cin和c ...
- 《C++primer》v5 第6章 函数 读书笔记 习题答案
6.1 实参是在函数调用处填写的参数.形参是在函数体使用的参数. 实参是形参的初始值. 具体参见:http://blog.163.com/zhengguo_li/blog/static/7030148 ...
- 《C++primer》v5 第5章 语句 读书笔记 习题答案
5.1 空语句只有一个";".如果什么也不想做可以使用空语句. 5.2 用花括号{}括起来的叫块,也叫复合语句.有多条语句作用在同一个作用域时,需要用花括号括起来. 5.3 降低了 ...
- 《C++primer》v5 第4章 表达式 读书笔记 习题答案
4.1 105 4.2 *vec.begin()=*(vec.begin())//先调用点运算符,再解引用 *vec.begin()+1=(*vec.begin())+1//先解引用,再加一 4.3略 ...
- 《C++primer》v5 第3章 字符串、向量和数组 读书笔记 习题答案
本章问题 1.char *p="hello world";与char p[]="hello world"的问题. 简单说前者是一个指向字符串常量的指针,后者是一 ...
- 《C++primer》v5 第8章 IO库 读书笔记 习题答案
8.1.8.2 这一章不咋会啊.. istream &read(istream &is) { int a; auto old_state=is.rdstate(); is.clear( ...
- 《C++primer》v5 第2章 变量和基本类型 读书笔记 习题答案
2.1 int,long long ,short 可表示范围和占用内存空间不同.具体与计算机有关. 无符号类型只能表示0和正数,带符号类型可以表示负数,0,正数. float是单精度,一般占用4个字节 ...
- C++primer(第五版)读书笔记&习题解答---CHAPTER 3
C++标准库类型包括:string,vector和迭代器,其中string是可变长的字符序列,vector存放的是某种给定类型对象的可变长序列,迭代器是string和vector的配套类型,常被用于访 ...
- C++ Primer(第五版)读书笔记 & 习题解答 --- Chapter 3
Chapter 3.1 1. using声明具有如下的形式: using namespace::name; Chapter 3.2 1. C++标准一方面对库类型所提供的操作做了规定,另一方面也对库的 ...
随机推荐
- message from server: "Host 'XXX' is not allowed to connect to this MySQL server
Access denied for user 'root'@'XXXXX' (using password: YES) mysql命令不正确造成: grant all privileges on *. ...
- Windows下 Maven 使用 阿里云镜像配置
新建或者修改文件: C:\Users\user\.m2\settings.xml <settings xmlns="http://maven.apache.org/SETTINGS/1 ...
- asp.net Lodop实现批量打印
1.列表(前台) <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="w_stu ...
- 【WebGoat习题解析】AJAX Security->Insecure Client Storage
绕过前端验证可以通过两种办法:一是利用开发者工具进行debug:二是利用burpsuite直接抓取.本题解决思路如下: STAGE 1: For this exercise, your mission ...
- python SimpleHTTPRequestHandler初探
1,转自 https://blog.gtwang.org/web-development/python-simplehttpserver-web-server/ 如果你急需一个简单的Web Serve ...
- C++笔记(1)explicit构造函数
按照默认规定,只有一个参数的构造函数也定义了一个隐式转换,将该构造函数对应数据类型的数据转换为该类对象,如下面所示: class String { String ( const char* p ); ...
- 如何修改file控件
在移动web开发过程中,常常会用到input file这控件,但css不能修改其样式往往让开发者很头疼,直接把他放到页面上又不美观: 下面介绍的方法,可以将该控件的显示样式替换成一个图标: 该方法 ...
- Centos下MySQL主从同步配置
说明:由于MySQL不同版本之间的(二进制日志)binlog格式可能会不一样, 因此最好的搭配组合是Master的MySQL版本和Slave的版本相同或者更低,Master的版本肯定不能高于Slave ...
- linux head、tail、sed、cut、grep、find
head用法: head 参数 文件名 -cn:显示前n个字节 -n:显示前n行 例子:head -c20 1.txt 显示1.txt文件中前20个字符 ls | head -20:显示前20 ...
- 10.6 CCPC northeast
1001 Minimum's Revenge 点的编号从 1 到 n ,u v 的边权是 LCM(u,v) ,求这个图的最下生成树 搞成一颗以 1 为 根 的菊花树 ---------------- ...