#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
一个小彩蛋,来看看这几个变量都是什么类型的,各有什么特点和区别?