引自C++Primer第四版中的类的例子,稍作修改并啰嗦了一些注释,用来回顾C++面向对象的基本知识。
Sales_item(string book):
isbn(book),units_sold(0),revenue(0.0) //按数据声明的顺序进行初始化
{
cout<<"structor with parameters"<<endl;
}
/*这里不定义自己的复制构造函数,默认采用合成的版本,
当有数据成员表示在构造函数中分配资源时(例如指针),必须自己定义复制构造函数*/
/*复合赋值操作符应定义为类的成员,但不是必须这样做
(赋值=、下标[]、调用()、成员访问箭头->这些操作符必须定义为成员函数)*/
//类定义了+操作符,逻辑上也应该定义+=操作符
Sales_item& operator+=(const Sales_item&);
double avg_price() const; //const 成员函数不能改变数据成员,唯一的例外是mutable(可变数据成员)
bool same_isbn(const Sales_item &rhs) const //类内部定义的函数默认为inline
{
return isbn == rhs.isbn;
}
~Sales_item(){cout<<"destructor run"<<endl;}; //析构函数
private:
string isbn;
unsigned units_sold;
double revenue;
};
inline double Sales_item::avg_price() const //可以在类内部声明时或类外部定义时说明成员函数为inline
{
if(units_sold)
return revenue/units_sold;
else
return 0;
}
istream& operator>>(istream& in,Sales_item& s)//输入操作符的重载,符合标准库
{
double price;
in>>s.isbn>>s.units_sold>>price;
if(in) //输入无错误时才处理数据
s.revenue=s.units_sold*price;
else //否则应该重设类的所有数据
s=Sales_item();
return in;
}
ostream& operator<<(ostream& out,const Sales_item& s)//输出操作符的重载,符合标准库
{
//格式应该在必要的前提下尽可能少,更具体的格式由用户控制
out<<s.isbn<<"/t"<<s.units_sold<<"/t"<<s.revenue<<"/t"<<s.avg_price();
return out;
}
Sales_item& Sales_item::operator +=(const Sales_item& rhs) //复合赋值操作符应返回左操作数的引用(隐含的this)
{
units_sold += rhs.units_sold;
revenue +=rhs.revenue;
return *this;
}
/* 算术操作符、关系操作符、相等操作符、位操作符最好定义为普通非成员函数 */
//利用复合赋值实现加法操作,无需再对每一数据成员单独操作,也不需要声明为友员
Sales_item operator+(const Sales_item& lhs,const Sales_item& rhs)//形参为const引用避免复制
{
Sales_item ret(lhs);
ret +=rhs;
return ret;
}
//相等操作符的定义
inline bool operator==(const Sales_item& lhs,const Sales_item& rhs)
{
return lhs.units_sold==rhs.units_sold && lhs.revenue==rhs.revenue && lhs.same_isbn(rhs);
}
//利用相等操作符定义!=操作符
inline bool operator!=(const Sales_item& lhs,const Sales_item& rhs)
{
return !(lhs==rhs);
}
int main()
{
string book("999-9");
Sales_item item1,item2;
cin>>item1>>item2;
Sales_item item3(item2); //调用合成的复制构造函数,因为我们并没有显式定义自己的版本
Sales_item item4=item1; //不是没有定义=的重载吗?因为赋值、取地址、逗号操作符对类类型操作数有默认含义
Sales_item item5; //调用第一个不带参数的构造函数
Sales_item item6("999-9"); //调用第二个带一个参数的构造函数
if(item1 == item2)
cout<<"the two items are the same"<<endl;
if(item1 != item2)
cout<<"the two items are not the same"<<endl;
if(item1.same_isbn(item2))
{
cout<<"ADD RESULT:/n"<<item1+item2<<endl;
item1 +=item2;
cout<<item1<<endl;
}
else
cerr<<"CAN NOT ADD,DATA MUST REFER TO SAME ISBN"<<endl;
cout<<item3<<endl;
cout<<item4<<endl;
cout<<item5<<endl;
cout<<item6<<endl;
cout<<item6.same_isbn(book)<<endl;//接受一个string的构造函数从book生成一个临时的Sales_item对象作为参数传给item6.same_isbn()
//有时这并不是个好主意,可以在构造函数前加explicit来防止这种情况的发生
return 0;
}