C++Primer第五版 習題答案 【總目錄】:https://blog.csdn.net/Dust_Evc/article/details/114334124
7.1
#include <iostream>
#include <string>
using std::cin; using std::cout; using std::endl; using std::string;
struct Sales_data
{
string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
int main()
{
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 = trans;
}
}
cout << total.bookNo << " " << total.units_sold << " " << total.revenue << endl;
}
else
{
std::cerr << "No data?!" << std::endl;
return -1;
}
return 0;
}
7.2
檔案名命名為:Sales_data_7_2.h,后面習題需要使用該頭檔案,
#pragma once
#ifndef SALES_DATA_7_2_H
#define SALES_DATA_7_2_H
#include <string>
#include <iostream>
using namespace std;
struct Sales_data
{
// 資料成員和2.6.1節 (第64頁)相比沒有改變
string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
// 新成員:關于Sales_data物件的操作
string isbn()
const { return bookNo; }
Sales_data& combine(const Sales_data&);
};
Sales_data& Sales_data::combine(const Sales_data& rhs)
{
units_sold += rhs.units_sold; //等同于this.units_sold += rhs.units_sold
revenue += rhs.revenue; //等同于this.revenue += rhs.revenue
return *this; //回傳呼叫該函式的物件,即this所系結的物件
}
#endif // !SALES_DATA_7_2_H
7.3
#include "Sales_data_7_2.h"
int main()
{
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); //total的地址被系結到combine定義中隱式的this引數上,回傳型別是Sales_data&
else
{
cout << total.bookNo << " " << total.units_sold << " " << total.revenue << endl;
total = trans;
}
}
cout << total.bookNo << " " << total.units_sold << " " << total.revenue << endl;
}
else
{
cerr << "No data?!" << endl;
return -1;
}
return 0;
}
7.4
#pragma once
#ifndef PERSON_7_4_H
#define PERSON_7_4_H
#include <string>
using namespace std;
struct Person
{
string Name, Address;
};
#endif // !PERSON_7_4_H
7.5
#pragma once
#ifndef PERSON_7_5_H
#define PERSON_7_5_H
#include <string>
using namespace std;
struct Person
{
//定義資料成員
string Name, Address;
//定義成員函式(方法)
string& const Get_Name() //只可訪問,不可修改
{ return Name; }
string& const Get_Address() //只可訪問,不可修改
{ return Address; }
};
#endif // !PERSON_7_5_H
應該是const的,因為常量的Person物件也需要使用這些函式操作,
7.6
檔案名命名為:Sales_data_7_6.h,后面習題需要使用該頭檔案,
#pragma once
#ifndef SALES_DATA_7_6_H
#define SALES_DATA_7_6_H
#include <string>
#include <iostream>
using namespace std;
struct Sales_data
{
// 資料成員
string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
// 新成員:關于Sales_data物件的操作
string isbn()
const { return bookNo; }
Sales_data& combine(const Sales_data&);
};
//類外函式定義
Sales_data& Sales_data::combine(const Sales_data& rhs)
{
units_sold += rhs.units_sold; //等同于this.units_sold += rhs.units_sold
revenue += rhs.revenue; //等同于this.revenue += rhs.revenue
return *this; //回傳呼叫該函式的物件,即this所系結的物件
}
istream &read(istream &is, Sales_data &item) //因為IO類屬于不能被拷貝的型別,因此只能通過參考來傳遞它們
{
double price = 0;
is >> item.bookNo >> item.units_sold >> price;
item.revenue = item.units_sold * price;
return is;
}
ostream &print(ostream &os, const Sales_data &item) //因為IO類屬于不能被拷貝的型別,因此只能通過參考來傳遞它們
{
os << item.isbn() << " " << item.units_sold << " " << item.revenue;
return os;
}
Sales_data add(const Sales_data &item1, const Sales_data &item2)
{
Sales_data sum = item1;
sum.combine(item2);
return sum;
}
#endif // !SALES_DATA_7_6_H
7.7
#include "Sales_data_7_6.h"
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;
return -1;
}
return 0;
}
7.8
因為read函式中需要改變物件的內容,而print函式中不需改變物件的內容,
7.9
#pragma once
#ifndef PERSON_7_9_H
#define PERSON_7_9_H
#include <string>
#include <iostream>
using namespace std;
struct Person
{
//定義資料成員
string Name, Address;
//定義成員函式(方法)
string& const Get_Name() //只可訪問,不可修改
{ return Name; }
string& const Get_Address() //只可訪問,不可修改
{ return Address; }
};
istream &read(istream &is, Person &item)
{
is >> item.Name >> item.Address;
return is;
}
ostream &print(ostream &os, const Person &item)
{
os << item.Name << " " << item.Address << " " << endl;
return os;
}
#endif // !PERSON_7_9_H
7.10
read 函式的回傳值是 istream 物件,if陳述句中條件部分的作用是從輸入流中讀取資料給兩個data物件,
7.11
Sales_data_7_11.h
#pragma once
#ifndef SALES_DATA_7_11_H
#define SALES_DATA_7_11_H
#include <string>
#include <iostream>
using namespace std;
struct Sales_data
{
// 資料成員(2.6節)
string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
// 新成員:關于Sales_data物件的操作(7.1.2節)
string isbn() const
{
return bookNo;
}
Sales_data& combine(const Sales_data&);
//新增類內建構式(7.1.4節),建構式名字與類名相同
Sales_data() = default; //此種情況,指令編譯器執行合成的默認建構式來初始化
Sales_data(istream &is);
Sales_data(const string &s) : bookNo(s) { }; 建構式中未給定初始值的部分,利用資料成員初始值進行初始化
Sales_data(const string &s, unsigned n, double p) : bookNo(s), units_sold(n), revenue(n*p) { };
};
//類外函式定義(7.1.3節)
Sales_data& Sales_data::combine(const Sales_data& rhs)
{
units_sold += rhs.units_sold; //等同于this.units_sold += rhs.units_sold
revenue += rhs.revenue; //等同于this.revenue += rhs.revenue
return *this; //回傳呼叫該函式的物件,即this所系結的物件
}
istream &read(istream &is, Sales_data &item) //因為IO類屬于不能被拷貝的型別,因此只能通過參考來傳遞它們
{
double price = 0;
is >> item.bookNo >> item.units_sold >> price;
item.revenue = item.units_sold * price;
return is;
}
ostream &print(ostream &os, const Sales_data &item) //因為IO類屬于不能被拷貝的型別,因此只能通過參考來傳遞它們
{
os << item.isbn() << " " << item.units_sold << " " << item.revenue;
return os;
}
Sales_data add(const Sales_data &item1, const Sales_data &item2)
{
Sales_data sum = item1;
sum.combine(item2);
return sum;
}
//新增類外建構式(7.1.4節)
Sales_data::Sales_data(istream &is) //此建構式初始值串列是空的,通過函式體進行初始化
{
read(is, *this); //從is中讀取一條交易資訊然后存入this所系結的物件中
}
#endif // !SALES_DATA_7_11_H
cpp檔案
#include "Sales_data_7_11.h"
int main() // 逐步執行來明白建構式的運行原理
{
Sales_data item1; //建構式中未給定初始值的部分,利用資料成員初始值進行初始化
print(cout, item1) << endl;
Sales_data item2("0-201-88954-4"); //白字item2對應的就是頭檔案建構式定義中的白字Sales_data
print(cout, item2) << endl;
Sales_data item3("0-201-88954-4", 5, 20.00); //建構式中給定初始值的情況,無需利用資料成員初始值進行初始化
print(cout, item3) << endl;
Sales_data item4(cin); //使用建構式初始化時,整體語法與類外建構式的定義形式相似
print(cout, item4) << endl;
return 0;
}
7.12
#pragma once
#ifndef SALES_DATA_7_12_H
#define SALES_DATA_7_12_H
#include <string>
#include <iostream>
using namespace std;
//為將類外建構式移到類內,需要先加下面兩行宣告read,否則第31行報錯:'read' identifier not found
struct Sales_data;
istream &read(istream &is, Sales_data &item);
struct Sales_data
{
// 資料成員(2.6節)
string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
// 新成員:關于Sales_data物件的操作(7.1.2節)
string isbn() const
{
return bookNo;
}
Sales_data& combine(const Sales_data&);
//新增類內建構式(7.1.4節),建構式名字與類名相同
Sales_data() = default; //此種情況,指令編譯器執行合成的默認建構式來初始化
Sales_data(istream &is) { read(is, *this); }; //將7.11.h中的類外建構式移到類內
Sales_data(const string &s) : bookNo(s) { }; 建構式中未給定初始值的部分,利用資料成員初始值進行初始化
Sales_data(const string &s, unsigned n, double p) : bookNo(s), units_sold(n), revenue(n*p) { };
};
//類外函式定義(7.1.3節)
Sales_data& Sales_data::combine(const Sales_data& rhs)
{
units_sold += rhs.units_sold; //等同于this.units_sold += rhs.units_sold
revenue += rhs.revenue; //等同于this.revenue += rhs.revenue
return *this; //回傳呼叫該函式的物件,即this所系結的對象
}
istream &read(istream &is, Sales_data &item) //因為IO類屬于不能被拷貝的型別,因此只能通過參考來傳遞它們
{
double price = 0;
is >> item.bookNo >> item.units_sold >> price;
item.revenue = item.units_sold * price;
return is;
}
ostream &print(ostream &os, const Sales_data &item) //因為IO類屬于不能被拷貝的型別,因此只能通過參考來傳遞它們
{
os << item.isbn() << " " << item.units_sold << " " << item.revenue;
return os;
}
Sales_data add(const Sales_data &item1, const Sales_data &item2)
{
Sales_data sum = item1;
sum.combine(item2);
return sum;
}
#endif // !SALES_DATA_7_12_H
7.13
#include "Sales_data_7_12.h"
int main()
{
Sales_data total(cin); //【★★】
if (!total.isbn().empty()) //【★★】
{
istream &is = cin; //【★★★★】
while (is) //【★★】
{
Sales_data trans(is); //【★★】
if (total.isbn() == trans.bookNo)
{
total.combine(trans);
}
else
{
print(cout, total);
total = trans;
}
}
print(cout, total);
}
else
{
cerr << "No data?!" << endl;
return -1;
}
return 0;
}
7.14
撰寫的類內建構式如下:
Sales_data() : units_sold(0) , revenue(0) { }
7.15
#pragma once
#ifndef PERSON_7_15_H
#define PERSON_7_15_H
#include <string>
#include <iostream>
using namespace std;
struct Person;
istream &read(istream &is, Person &item);
struct Person
{
//定義資料成員 (Ex_7.4)
string Name, Address;
//定義成員函式(方法) (Ex_7.5)
string& const Get_Name() //只可訪問,不可修改
{
return Name;
}
string& const Get_Address() //只可訪問,不可修改
{
return Address;
}
//定義建構式(Ex_7.15)
Person() = default;
Person(istream &is) { read(is, *this); };
Person(string &NM) : Name(NM) { };
Person(string &NM, string &ADD) : Name(NM), Address(ADD) { };
};
//定義類外函式 (Ex_7.9)
istream &read(istream &is, Person &item)
{
is >> item.Name >> item.Address;
return is;
}
ostream &print(ostream &os, const Person &item)
{
os << item.Name << " " << item.Address << " " << endl;
return os;
}
#endif // !PERSON_7_15_H
7.16
在類的定義中對于訪問說明符出現的位置和次數沒有限定,每個訪問說明符指定了接下來的成員的訪問級別,其有效范圍直到出現下一個訪問說明符或者達到類的結尾處為止,
如果某個成員需要在整個程式內都被訪問,那么它應該定義為 public; 如果某個成員只能在類內部訪問,那么它應該定義為 private,
7.17
class 和 struct 的唯一區別是默認的訪問級別不同,
struct關鍵字,定義在第一個訪問說明符之前的成員是public 的;相反,class關鍵字,定義在第一個訪問說明符之前的成員是private的,
7.18
將類內部分成員設定為外部不可見,而提供部分介面給外面,這樣的行為叫做封裝,
封裝隱藏了具體的實作,當我們使用某個抽象資料型別時,只需要考慮它提供什么介面操作,而不用去考慮它的具體實作,
7.19
建構式、getName()、getAddress() 函式將設為 public,name 和 address 將設為private,
函式是暴露給外部的介面,因此要設為public;而資料則應該隱藏讓外部不可見,
7.20
利: 與當前類有關的介面函式能直接訪問類的私有變數,
弊: 犧牲了封裝性與可維護性,
7.21
#pragma once
#ifndef SALES_DATA_7_21_H
#define SALES_DATA_7_21_H
#include <string>
#include <iostream>
using namespace std;
//為將類外建構式移到類內,需要先加下面兩行宣告read,否則第31行報錯:'read' identifier not found
struct Sales_data;
istream &read(istream &is, Sales_data &item);
struct Sales_data
{
//友元宣告(Ex_7.21)
friend istream &read(istream &is, Sales_data &item);
friend ostream &print(ostream &os, const Sales_data &item);
friend Sales_data add(const Sales_data &item1, const Sales_data &item2);
private:
// 資料成員(2.6節)
string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
public:
// 新成員:關于Sales_data物件的操作(7.1.2節)
string isbn() const
{
return bookNo;
}
Sales_data& combine(const Sales_data&);
//新增類內建構式(7.1.4節),建構式名字與類名相同
Sales_data() = default; //此種情況,指令編譯器執行合成的默認建構式來初始化
Sales_data(istream &is) { read(is, *this); }; //將7.11.h中的類外建構式移到類內
Sales_data(const string &s) : bookNo(s) { }; 建構式中未給定初始值的部分,利用資料成員初始值進行初始化
Sales_data(const string &s, unsigned n, double p) : bookNo(s), units_sold(n), revenue(n*p) { };
};
//類外函式定義(7.1.3節)
Sales_data& Sales_data::combine(const Sales_data& rhs)
{
units_sold += rhs.units_sold; //等同于this.units_sold += rhs.units_sold
revenue += rhs.revenue; //等同于this.revenue += rhs.revenue
return *this; //回傳呼叫該函式的物件,即this所系結的物件
}
istream &read(istream &is, Sales_data &item) //因為IO類屬于不能被拷貝的型別,因此只能通過參考來傳遞它們
{
double price = 0;
is >> item.bookNo >> item.units_sold >> price;
item.revenue = item.units_sold * price;
return is;
}
ostream &print(ostream &os, const Sales_data &item) //因為IO類屬于不能被拷貝的型別,因此只能通過參考來傳遞它們
{
os << item.isbn() << " " << item.units_sold << " " << item.revenue;
return os;
}
Sales_data add(const Sales_data &item1, const Sales_data &item2)
{
Sales_data sum = item1;
sum.combine(item2);
return sum;
}
#endif // !SALES_DATA_7_21_H
7.22
#pragma once
#ifndef PERSON_7_22_H
#define PERSON_7_22_H
#include <string>
#include <iostream>
using namespace std;
struct Person;
istream &read(istream &is, Person &item);
struct Person
{
//友元宣告(Ex_7.21)
friend istream &read(istream &is, Person &item);
friend ostream &print(ostream &os, const Person &item);
private:
//定義資料成員 (Ex_7.4)
string Name, Address;
public:
//定義成員函式(方法) (Ex_7.5)
string& const Get_Name() //只可訪問,不可修改
{
return Name;
}
string& const Get_Address() //只可訪問,不可修改
{
return Address;
}
//定義建構式(Ex_7.15)
Person() = default;
Person(istream &is) { read(is, *this); };
Person(string &NM) : Name(NM) { };
Person(string &NM, string &ADD) : Name(NM), Address(ADD) { };
};
//定義類外函式 (Ex_7.9)
istream &read(istream &is, Person &item)
{
is >> item.Name >> item.Address;
return is;
}
ostream &print(ostream &os, const Person &item)
{
os << item.Name << " " << item.Address << " " << endl;
return os;
}
#endif // !PERSON_7_22_H
7.23
#ifndef CP5_ex7_23_h
#define CP5_ex7_23_h
#include <string>
class Screen
{
public:
using pos = std::string::size_type;
Screen() = default;
Screen(pos ht, pos wd, char c) :height(ht), width(wd), contents(ht*wd, c) {}
char get() const { return contents[cursor]; }
char get(pos r, pos c) const { return contents[r*width + c]; }
private:
pos cursor = 0;
pos height = 0;
pos width = 0;
std::string contents;
};
#endif
7.24
#ifndef CP5_ex7_24_h
#define CP5_ex7_24_h
#include <string>
class Screen
{
public:
using pos = std::string::size_type;
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]; }
char get(pos r, pos c) const { return contents[r*width + c]; }
private:
pos cursor = 0;
pos height = 0;
pos width = 0;
std::string contents;
};
#endif
7.25
能,
Screen 的成員只有內置型別和 string,因此能安全地依賴于拷貝和賦值操作的默認版本,管理動態記憶體的類則不能依賴于拷貝和賦值操作的默認版本,而且也應該盡量使用string 和 vector 來避免動態管理記憶體的復雜性,
7.26
#ifndef CP5_ex7_26_h
#define CP5_ex7_26_h
#include <string>
#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);
friend Sales_data add(const Sales_data &lhs, const Sales_data &rhs);
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(n*p) {}
Sales_data(std::istream &is) { read(is, *this); }
std::string isbn() const { return bookNo; };
Sales_data& combine(const Sales_data&);
private:
inline double avg_price() const;
private:
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
inline
double Sales_data::avg_price() const
{
return units_sold ? revenue / units_sold : 0;
}
std::istream &read(std::istream &is, Sales_data &item);
std::ostream &print(std::ostream &os, const Sales_data &item);
Sales_data add(const Sales_data &lhs, const Sales_data &rhs);
#endif
7.27
exercise7_27.h
#pragma once
#ifndef CP5_ex7_27_h
#define CP5_ex7_27_h
#include <string>
#include <iostream>
class Screen
{
public:
using pos = std::string::size_type;
Screen() = default; // 1
Screen(pos ht, pos wd) :height(ht), width(wd), contents(ht*wd, ' ') {} // 2
Screen(pos ht, pos wd, char c) :height(ht), width(wd), contents(ht*wd, c) {} // 3
char get() const { return contents[cursor]; }
char get(pos r, pos c) const { return contents[r*width + c]; }
inline Screen& move(pos r, pos c);
inline Screen& set(char c);
inline Screen& set(pos r, pos c, char ch);
const Screen& display(std::ostream &os) const { do_display(os); return *this; }
Screen& display(std::ostream &os) { do_display(os); return *this; }
private:
void do_display(std::ostream &os) const { os << contents; }
private:
pos cursor = 0;
pos height = 0, width = 0;
std::string contents;
};
inline Screen& Screen::move(pos r, pos c)
{
cursor = r * width + c;
return *this;
}
inline Screen& Screen::set(char c)
{
contents[cursor] = c;
return *this;
}
inline Screen& Screen::set(pos r, pos c, char ch)
{
contents[r*width + c] = ch;
return *this;
}
#endif
cpp
#include "exercise7_27.h"
int main()
{
Screen myScreen(5, 5, 'X');
myScreen.move(4, 0).set('#').display(std::cout);
std::cout << "\n";
myScreen.display(std::cout);
std::cout << "\n";
return 0;
}
7.28
如果回傳型別是Screen,那么move回傳的是 *this 的一個副本,因此set函式只能改變臨時副本而不能改變myScreen的值,
7.29
推測正確,
7.30
優點:
1:程式的意圖更明確,當需要將一個物件作為整體參考而不是參考物件的一個成員時,使用this,則該函式回傳對呼叫該函式的物件的參考,
2:可以非常明確地指出訪問的是呼叫該函式的物件的成員,且可以在成員函式中使用與資料成員同名的形參,
缺點:有時候顯得有點多余,
7.31
class Y;
class X{
Y* y = nullptr;
};
class Y{
X x;
};
7.32
#ifndef CP5_ex7_32_h
#define CP5_ex7_32_h
#include <vector>
#include <iostream>
#include <string>
class Screen;
class Window_mgr
{
public:
using ScreenIndex = std::vector<Screen>::size_type;
inline void clear(ScreenIndex);
private:
std::vector<Screen> screens;
};
class Screen
{
friend void Window_mgr::clear(ScreenIndex);
public:
using pos = std::string::size_type;
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]; }
char get(pos r, pos c) const { return contents[r*width + c]; }
inline Screen& move(pos r, pos c);
inline Screen& set(char c);
inline Screen& set(pos r, pos c, char ch);
const Screen& display(std::ostream& os) const { do_display(os); return *this; }
Screen& display(std::ostream& os) { do_display(os); return *this; }
private:
void do_display(std::ostream &os) const { os << contents; }
private:
pos cursor = 0;
pos width = 0, height = 0;
std::string contents;
};
inline void Window_mgr::clear(ScreenIndex i)
{
Screen& s = screens[i];
s.contents = std::string(s.height*s.width,' ');
}
inline Screen& Screen::move(pos r, pos c)
{
cursor = r*width + c;
return *this;
}
inline Screen& Screen::set(char c)
{
contents[cursor] = c;
return *this;
}
inline Screen& Screen::set(pos r, pos c, char ch)
{
contents[r*width + c] = ch;
return *this;
}
#endif
7.33
未定義識別符號 pos,應該改為:
Screen::pos Screen::size() const
{
return height * width;
}
7.34
在 dummy_fcn(pos height)函式中會出現“未定義的識別符號pos”,
型別名的定義通常出現在類的開始處,這樣就能確保所有使用該型別的成員都出現在類名的定義之后,
7.35
在類中,如果成員使用了外層作用域中的某個名字,而該名字代表一種型別,則類不能在之后重新定義該名字,
因此重復定義 Type 是錯誤的行為,
7.36
應該改為:
struct X {
X (int i, int j): base(i), rem(base % j) {}
int base, rem;
};
7.37
Sales_data first_item(cin); // 使用 Sales_data(std::istream &is) ; 各成員值從輸入流中讀取
int main() {
Sales_data next; // 使用默認建構式 bookNo = "", cnt = 0, revenue = 0.0
// 使用 Sales_data(std::string s = ""); bookNo = "9-999-99999-9", cnt = 0, revenue = 0.0
Sales_data last("9-999-99999-9");
}
7.38
Sales_data(std::istream &is = std::cin) { read(is, *this); }
7.39
不合法,當你呼叫 Sales_data() 建構式時,無法區分是哪個多載,
7.40
(a) Book.
?
class Book
{
public:
Book(unsigned isbn, std::string const& name, std::string const& author, std::string const& pubdate)
:isbn_(isbn), name_(name), author_(author), pubdate_(pubdate)
{ }
explicit Book(std::istream &in)
{
in >> isbn_ >> name_ >> author_ >> pubdate_;
}
private:
unsigned isbn_;
std::string name_;
std::string author_;
std::string pubdate_;
};
?
7.41
頭檔案
#ifndef CP5_ex7_41_h
#define CP5_ex7_41_h
#include <string>
#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);
friend Sales_data add(const Sales_data &lhs, const Sales_data &rhs);
public:
Sales_data(const std::string &s, unsigned n, double p) :bookNo(s), units_sold(n), revenue(n*p)
{
std::cout << "Sales_data(const std::string&, unsigned, double)" << std::endl;
}
Sales_data() : Sales_data("", 0, 0.0f)
{
std::cout << "Sales_data()" << std::endl;
}
Sales_data(const std::string &s) : Sales_data(s, 0, 0.0f)
{
std::cout << "Sales_data(const std::string&)" << std::endl;
}
Sales_data(std::istream &is);
std::string isbn() const { return bookNo; }
Sales_data& combine(const Sales_data&);
private:
inline double avg_price() const;
private:
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
inline
double Sales_data::avg_price() const
{
return units_sold ? revenue / units_sold : 0;
}
std::istream &read(std::istream &is, Sales_data &item);
std::ostream &print(std::ostream &os, const Sales_data &item);
Sales_data add(const Sales_data &lhs, const Sales_data &rhs);
#endif
cpp檔案
#include "exercise7_41.h"
Sales_data::Sales_data(std::istream &is) : Sales_data()
{
std::cout << "Sales_data(istream &is)" << std::endl;
read(is, *this);
}
Sales_data& Sales_data::combine(const Sales_data& rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *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;
return os;
}
Sales_data add(const Sales_data &lhs, const Sales_data &rhs)
{
Sales_data sum = lhs;
sum.combine(rhs);
return sum;
}
main檔案
#include "exercise7_41.h"
using std::cout; using std::endl;
int main()
{
cout << "1. default way: " << endl;
cout << "----------------" << endl;
Sales_data s1;
cout << "\n2. use std::string as parameter: " << endl;
cout << "----------------" << endl;
Sales_data s2("CPP-Primer-5th");
cout << "\n3. complete parameters: " << endl;
cout << "----------------" << endl;
Sales_data s3("CPP-Primer-5th", 3, 25.8);
cout << "\n4. use istream as parameter: " << endl;
cout << "----------------" << endl;
Sales_data s4(std::cin);
return 0;
}
7.42
class Book
{
public:
Book(unsigned isbn, std::string const& name, std::string const& author, std::string const& pubdate)
:isbn_(isbn), name_(name), author_(author), pubdate_(pubdate)
{ }
Book(unsigned isbn) : Book(isbn, "", "", "") {}
explicit Book(std::istream &in)
{
in >> isbn_ >> name_ >> author_ >> pubdate_;
}
private:
unsigned isbn_;
std::string name_;
std::string author_;
std::string pubdate_;
};
7.43
class NoDefault {
public:
NoDefault(int i) { }
};
class C {
public:
C() : def(0) { }
private:
NoDefault def;
};
7.44
不合法,因為 NoDefault 沒有默認建構式,
7.45
合法,因為 C 有默認建構式,
7.46
- (a) 不正確,如果我們的類沒有顯式地定義建構式,那么編譯器就會為我們隱式地定義一個默認建構式,并稱之為合成的默認建構式,
- (b) 不完全正確,為每個引數都提供了默認值的建構式也是默認建構式,
- (c) 不正確,哪怕沒有意義的值也需要初始化,
- (d) 不正確,只有當一個類沒有定義任何建構式的時候,編譯器才會生成一個默認建構式,
7.47
是否需要從 string 到 Sales_data 的轉換依賴于我們對用戶使用該轉換的看法,在此例中,這種轉換可能是對的,null_book 中的 string 可能表示了一個不存在的 ISBN 編號,
優點:
- 可以抑制建構式定義的隱式轉換
缺點:
- 為了轉換要顯式地使用建構式
7.48
這些定義和是不是 explicit 的無關,
7.49
?
(a) Sales_data &combine(Sales_data); // ok
(b) Sales_data &combine(Sales_data&); // error C2664: 無法將引數 1 從“std::string”轉換為“Sales_data &”
(c) Sales_data &combine(const Sales_data&) const; // 該成員函式是const 的,意味著不能改變物件,而 combine函式的本意就是要改變物件
?
7.50
?explicit Person(std::istream &is){ read(is, *this); }
7.51
假如我們有一個這樣的函式:
int getSize(const std::vector<int>&);
如果vector沒有將單引數建構式定義成 explicit 的,我們就可以這樣呼叫:
getSize(34);
很明顯這樣呼叫會讓人困惑,函式實際上會初始化一個擁有34個元素的vector的臨時量,然后回傳34,但是這樣沒有任何意義,而 string 則不同,string 的單引數建構式的引數是 const char * ,因此凡是在需要用到 string 的地方都可以用 const char * 來代替(字面值就是 const char *),如:
void print(std::string);
print("hello world");
7.52
Sales_data 類不是聚合類,應該修改成如下:
struct Sales_data {
std::string bookNo;
unsigned units_sold;
double revenue;
};
7.53
class Debug {
public:
constexpr Debug(bool b = true) : hw(b), io(b), other(b) { }
constexpr Debug(bool h, bool i, bool o) : hw(r), io(i), other(0) { }
constexpr bool any() { return hw || io || other; }
void set_hw(bool b) { hw = b; }
void set_io(bool b) { io = b; }
void set_other(bool b) { other = b; }
private:
bool hw; // runtime error
bool io; // I/O error
bool other; // the others
};
7.54
不能,constexpr 函式必須包含一個回傳陳述句,
7.55
不是,因為 std::string 不是字面值型別,
7.56
與類本身相關,而不是與類的各個物件相關的成員是靜態成員,其不與任何實體化物件系結,但是我們仍然可以使用類作用域運算子訪問靜態成員,加上static關鍵字即可宣告,
靜態成員能用于某些場景,而普通成員不能,
7.57
class Account {
public:
void calculate() { amount += amount * interestRate; }
static double rate() { return interestRate; }
static void rate(double newRate) { interestRate = newRate; }
private:
std::string owner;
double amount;
static double interestRate;
static constexpr double todayRate = 42.42;
static double initRate() { return todayRate; }
};
double Account::interestRate = initRate();
7.58
rate 應該是一個常量運算式,而類內只能初始化整型型別的靜態常量,所以不能在類內初始化vec,修改后如下:
// example.h
class Example {
public:
static constexpr double rate = 6.5;
static const int vecSize = 20;
static vector<double> vec;
};
// example.C
#include "example.h"
constexpr double Example::rate;
vector<double> Example::vec(Example::vecSize);
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/266998.html
標籤:其他
