#ifndef SALESITEM_H
// we're here only if SALESITEM_H has not yet been defined
#define SALESITEM_H
// Definition of Sales_item class and related functions goes here
#include <iostream>
#include <string>
class Sales_item {
// these declarations are explained section 7.2.1, p. 270
// and in chapter 14, pages 557, 558, 561
//友元函數用於非類成員函數但需要訪問類的內部成員變量,用friend聲明,定義時不需要friend
//自定義重載運算符有特定的函數名以及形參列表和返回值類型
//當函數中需要用到IO類型對象時,不管是作爲形參還是作爲返回值,都需要定義爲引用類型
//自定義重載運算符,其函數名稱都是operator再加上具體的運算符,形參列表取決於具體的運算符
//運算符的左右兩側運算對象,按照順序放在形參列表中
friend std::istream& operator>>(std::istream&, Sales_item&);
//將形參定義爲常量引用有兩個原因:1.定義爲引用,可以避免值傳遞 2.定義爲常量引用,
//則說明不能通過該引用修改實參的值
friend std::ostream& operator<<(std::ostream&, const Sales_item&);
friend bool operator<(const Sales_item&, const Sales_item&);
friend bool
operator==(const Sales_item&, const Sales_item&);
public:
// constructors are explained in section 7.1.4, pages 262 - 265
// default constructor needed to initialize members of built-in type
/*
class的默認訪問修飾符爲private,struct的默認訪問修飾符爲public
訪問修飾符的作用範圍一直到下一個訪問修飾符出現或者到類末尾爲止
*/
/*
在不提供構造函數時,編譯器會生成默認的構造函數
在提供任意一個構造函數時,編譯器不再提供默認構造函數,需要顯式的添加默認構造函數,即加上=default;
構造函數沒有返回值類型,函數名與類名一致,形參可爲空,可重載
*/
Sales_item() = default;//顯式添加默認構造函數,不需要函數體
/*
在形參列表後面加上構造函數初始值列表,格式爲
:成員變量1(對應形參)[,成員變量2(對應形參)]{}
*/
Sales_item(const std::string& book) : bookNo(book) { }
Sales_item(std::istream& is) { is >> *this; }
public:
// operations on Sales_item objects
// member binary operator: left-hand operand bound to implicit this pointer
/*
複合賦值運算符重載,這裏可以返回引用,是因爲函數返回隱式指針this所指對象,即其自身
一般情況下,返回值類型爲引用只有兩種情況:
1.同此情況,返回值就是this本身,不需要值拷貝
2.定義了局部的靜態變量,使得函數調用結束之後,該局部靜態變量並沒有被釋放
*/
Sales_item& operator+=(const Sales_item&);
// operations on Sales_item objects
/*
這裏return bookNo;其本質是return this->bookNo;this爲隱式參數,通過this來訪問調用成員函數的對象的成員變量
形參列表之後的const用於修改this指針的類型,使得函數內部不能修改this所指對象的內容,即此時this指針既是
頂部const(this爲頂部const是因爲this始終指向調用成員函數的對象,不能修改,不能重新指向),也是底部const
*/
std::string isbn() const { return bookNo; }
double avg_price() const;
// private members as before
private:
std::string bookNo; // implicitly initialized to the empty string
unsigned units_sold = 0; // explicitly initialized
double revenue = 0.0;
};
// used in chapter 10
//顯式聲明爲內聯inline函數
inline
bool compareIsbn(const Sales_item& lhs, const Sales_item& rhs)
{
return lhs.isbn() == rhs.isbn();
}
// nonmember binary operator: must declare a parameter for each operand
Sales_item operator+(const Sales_item&, const Sales_item&);
inline bool
operator==(const Sales_item& lhs, const Sales_item& rhs)
{
// must be made a friend of Sales_item
return lhs.units_sold == rhs.units_sold &&
lhs.revenue == rhs.revenue &&
lhs.isbn() == rhs.isbn();
}
inline bool
operator!=(const Sales_item& lhs, const Sales_item& rhs)
{
return !(lhs == rhs); // != defined in terms of operator==
}
// assumes that both objects refer to the same ISBN
Sales_item& Sales_item::operator+=(const Sales_item& rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
// assumes that both objects refer to the same ISBN
Sales_item
operator+(const Sales_item& lhs, const Sales_item& rhs)
{
Sales_item ret(lhs); // copy (|lhs|) into a local object that we'll return
ret += rhs; // add in the contents of (|rhs|)
return ret; // return (|ret|) by value
}
std::istream&
operator>>(std::istream& in, Sales_item& s)
{
double price;
in >> s.bookNo >> s.units_sold >> price;
// check that the inputs succeeded
if (in)
s.revenue = s.units_sold * price;
else
s = Sales_item(); // input failed: reset object to default state
return in;
}
std::ostream&
operator<<(std::ostream& out, const Sales_item& s)
{
out << s.isbn() << " " << s.units_sold << " "
<< s.revenue << " " << s.avg_price();
return out;
}
double Sales_item::avg_price() const
{
//units_sold = 1;代碼錯誤,提示表達式必須是可修改的左值,因爲該函數聲明爲const成員函數
//不能通過隱式this修改其成員變量
if (units_sold)
return revenue / units_sold;
else
return 0;
}
#endif
一個小彩蛋,來看看這幾個變量都是什麼類型的,各有什麼特點和區別?