练习7.11 在你的Sales_data类中添加构造函数,然后编写一段程序令其用到每个构造函数。
//Sale_data.h
#pragma once
#include <iostream>
#include <string>
using namespace std;
struct Sales_data {
Sales_data() = default;
Sales_data(const string &s): bookNo(s){}
Sales_data(const string &s, const unsigned cnt, const double p):
bookNo(s), units_sold(cnt), revenue(cnt*p){}
Sales_data(istream &is);
string isbn()const { return this->bookNo; }
Sales_data &combine(const Sales_data &other);
string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
istream &read(istream &is, Sales_data &item);
ostream &print(ostream &os, const Sales_data &item);
Sales_data add(const Sales_data &a, const Sales_data &b);
//Sale_data.cpp
#include"Sale_data.h"
Sales_data::Sales_data(istream &is) {
read(is, *this);
}
Sales_data &Sales_data::combine(const Sales_data &other) {
this->units_sold += other.units_sold;
this->revenue += other.revenue;
return *this;
}
istream &read(istream &is, Sales_data &item) {
double price;
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.bookNo << " " << item.units_sold << " " << item.revenue;
return os;
}
Sales_data add(const Sales_data &a, const Sales_data &b) {
Sales_data sum = a;
sum.combine(b);
return sum;
}
//main.cpp
#include"Sale_data.h"
int main(int argc, char **argv)
{
Sales_data a;
cout << a.bookNo << "++" << a.units_sold << "++" << a.revenue << endl;
Sales_data b("123");
cout << b.bookNo << "++" << b.units_sold << "++" << b.revenue << endl;
Sales_data c("1234", 5, 20);
cout << c.bookNo << "++" << c.units_sold << "++" << c.revenue << endl;
Sales_data d(cin);
cout << d.bookNo << "++" << d.units_sold << "++" << d.revenue << endl;
return 0;
}
练习7.12 把只接受一个istream
作为参数的构造函数移到类的内部。
//Sale_data.h
#pragma once
#include <iostream>
#include <string>
using namespace std;
struct Sales_data;
istream &read(istream &is, Sales_data &item);
struct Sales_data {
Sales_data() = default;
Sales_data(const string &s): bookNo(s){}
Sales_data(const string &s, const unsigned cnt, const double p):
bookNo(s), units_sold(cnt), revenue(cnt*p){}
Sales_data(istream &is) { read(is, *this); }
string isbn()const { return this->bookNo; }
Sales_data &combine(const Sales_data &other);
string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
ostream &print(ostream &os, const Sales_data &item);
Sales_data add(const Sales_data &a, const Sales_data &b);
可以提前声明结构体/函数。
//Sale_data.h
#pragma once
#include <iostream>
#include <string>
using namespace std;
struct Sales_data {
Sales_data() = default;
Sales_data(const string &s): bookNo(s){}
Sales_data(const string &s, const unsigned cnt, const double p):
bookNo(s), units_sold(cnt), revenue(cnt*p){}
Sales_data(istream &is) {
double price;
is >> this->bookNo >> this->units_sold >> price;
this->revenue = this->units_sold * price;
}
string isbn()const { return this->bookNo; }
Sales_data &combine(const Sales_data &other);
string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
istream &read(istream &is, Sales_data &item);
ostream &print(ostream &os, const Sales_data &item);
Sales_data add(const Sales_data &a, const Sales_data &b);
也可以直接把read的实现重写一下。
练习7.13 使用istream
构造函数重写第229页的程序。
#include"Sale_data.h"
int main(int argc, char **argv)
{
Sales_data total(cin);
if (!total.bookNo.empty()) {
while (true) {
Sales_data trans(cin);
if (trans.bookNo.empty()) break;
if (total.bookNo == trans.bookNo) {
total.combine(trans);
}
else {
print(cout, total) << endl;
total = trans;
}
}
print(cout, total) << endl;
}
else {
cerr << "No Data ?!" << endl;
}
return 0;
}
练习7.14 编写一个构造函数,令其用我们提供的类内初始值显式地初始化成员。
Sales_data(): units_sold(0) , revenue(0) { }
练习7.15 为你的 Person
类添加正确的构造函数。
struct Person;
std::istream &read(std::istream&, Person&);
class Person {
public:
Person() = default;
Person(const string &sname, const string &saddr) :name(sname), address(saddr) {}
Person(istream &is) { read(is, *this); }
string name;
string addr;
auto getName()const -> const string & { return this->name; }
auto getAddr()const -> const string & { return this->addr; }
};
练习7.16 在类的定义中对于访问说明符出现的位置和次数有限定吗?如果有,是什么?什么样的成员应该定义在public
说明符之后?什么样的成员应该定义在private
说明符之后?
没有限定次数,每个访问说明符指定了接下来的成员的访问计别,其有效范围直到出现下一个访问说明符或者到达类的结尾处位置。
构造函数和部分函数应声明为public
数据成员和作为实现部分的函数则应该声明为private
练习7.17 使用class
和 struct
时有区别吗?如果有,是什么?
class
和 struct
的唯一区别是默认的访问级别不同,struct默认为public
,class
默认为private
。
练习7.18 封装是何含义?它有什么用处?
封装可以保证部分类成员不可见,保证了数据的安全性;也可以让类的设计者可以自定义接口,实现更好和严谨的控制。封装可以令类的使用者聚焦于如何使用类,而不用去关心它是如何实现的。
练习7.19 在你的Person
类中,你将把哪些成员声明成public
的?哪些声明成private
的?解释你这样做的原因。
struct Person;
std::istream &read(std::istream&, Person&);
class Person {
public:
Person() = default;
Person(const string &sname, const string &saddr) :name(sname), address(saddr) {}
Person(istream &is) { read(is, *this); }
auto getName()const -> const string & { return this->name; }
auto getAddr()const -> const string & { return this->addr; }
private:
string name;
string addr;
};
数据应该被保护起来,使其不能随便被修改,所以声明为private
。构造函数和用于访问类内数据的函数要提供给使用者来创建和操作类,所以声明为public
。
练习7.20 友元在什么时候有用?请分别举出使用友元的利弊。
当某些类或函数需要访问某个类的私有成员时。
利:
- 使代码更灵活,方便编写一些与该类相关的函数和其他类。
弊:
- 牺牲了封装性和可维护性。