練習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 友元在什麼時候有用?請分別舉出使用友元的利弊。
當某些類或函數需要訪問某個類的私有成員時。
利:
- 使代碼更靈活,方便編寫一些與該類相關的函數和其他類。
弊:
- 犧牲了封裝性和可維護性。