除了重载的函数调用运算符operator()之外,其他重载运算符不能含有默认实参。
当以个重载的运算符是成员函数时,this绑定到左侧运算对象。成员运算符函数的(显式)参数比运算对象的数量少一个。
当运算符作用于内置类型的运算对象时,我们无法改变运算的含义。
这四个运算符不能被重载。
我们只能重载已有的运算符,不能发明新的。优先级和结合律不变。
data1 + data2;
operator+(data1,data2);
上述两个是等价调用。
因为重载运算符其实是函数调用,逻辑与、逻辑或、和逗号的运算对象求值顺序规则无法保留下来,因此,不应该被重载。
还有一个原因是的我们不重载逗号和取址运算符:c++语言已经定义了这两种运算符用于类类型对象时的特殊含义,所以一般不重载,否则它们的行为将异于常态,从而导致类用户无法适应。
赋值运算,左侧运算对象和右侧运算对象的值相等,并且运算符应该返回它左侧运算对象的一个引用。
成员函数还是非成员函数:
赋值(=)下标([ 调用( (和成员访问箭头(->运算符必须是成员函数。
复合运算符一般来说应该是成员,但非必须,只一点与赋值运算略有不同。
改变对象状态的运算符或者与给定类型密切相关的运算符,如递增、递减和解引用运算符,通常应该是成员。
具有对称性的运算符可能转换任意一端的运算对象,例如算术、想等性、关系和位运算符等,因此他们通常应该是普通非成员函数。
如果我们想提供含有类对象的混合型表达式,则运算符必须定义成非成员函数。如int和double相加。
当我们把运算符定义成成员函数时,它的左侧运算对象必须是运算符所属类的一个对象。
输出运算符的第一个参数是一个非常量ostream对象的引用,因为写入内容会改变其状态,是引用因为我们无法直接复制一个ostream对象。
第二个参数一般是一个常量的引用,该常量使我们想要打印的类类型。引用是因为我们希望避免复制实参。常量是不会改变内容。
为了与其他保持一致一般返回ostream形参。
ostream &operator<<(ostream &os , const sales_data &item)
os<<
return os;
输出运算符应该尽量减少格式操作,可以使用户来控制输出细节。不应该打印换行符。
与iostream标准库兼容的输入输出运算符必须是普通的分成员函数。
输入运算符的第一个参数是运算符将要读取的流额引用,第二个参数是将要读入到的( 非常量 )对象的引用,通常会返回某个给定流的引用。
istream &operator>>(istream &is , sales_data &item)
double price;
is >>price;
if(is)
= *price;
elseitem = sales_data( )
return is;
输入运算符必须处理输入可能失败的情况,而输出运算符不需要。
在执行输入运算时可能发生以下错误:
当流含有错误类型的数据时读取操作可能失败。
当读取操作到达文件末尾或者遇到输入流的其他错误是也会失败。
当读取操作发生错误时,输入运算符应该负责从错误中恢复。
虽然我们可以使用failbit,eofbit,badbit等错误标示,但最好是让标准库来标示错误。
算术和关系运算符定义成非成员函数,以允许左右的运算对象进行转换。因为这些运算符一般不需要改变运算对象的状态,所以形参都是常量引用。
如果定义了算术运算符,则一般也会定义一个对应的复合运算符。 符合允许符一般来说应该是成员,但非必须,只一点与赋值运算略有不同。
如果类同时定义了算术运算符合相关的复合赋值运算符,则通常情况下应该使用复合赋值运算符来实现算术运算符。
sales_data operator+(const sales_data &lhs , const sales_data &rhs)
sales_data sum = lhs;
sum +=rhs;
return sum;
bool operator ==const sales_data &lhs, const sales_data &rhs)
return &&
bool operator !=cosnt sales_data &lhs, const sales_data &rhs)
return !(lhs ==rhs);
如果某个类在逻辑上有相等的含义,则应该定义operator ==
特别因为关联容器和一些算法要用到小于运算符,所欲定义operator《会比较有用。
如果存在唯一一种逻辑可靠的《定义,则应该考虑为这个类定义《运算符。如果类同时还包含 ==这当且仅当《的定义和==产生的救国一致是才定义《运算符。
除了拷贝赋值和移动赋值,类还可以定义其他赋值运算符以使用别的类型作为右侧运算对象。例如vector,定义了第三中赋值运算符,元素列表作为参数。
vector v;
v = 为strvec添加这个运算符。
class strvec
const std::string& operator[ ]std::size_t n) const
private:
std::string *elements;
在迭代器类中通常有递增和递减运算符,不必须是成员函数,但因为它们改变的正好是所操作对象的状态,所以建议使用成员函数。
为了与内置版本一致,前置返回的是递增后的对象的引用。后值饭会的是对象的原值,返回的形式是一个值而非引用。
/前置版本。
class strblobptr{
public:
strblobptr& operator++
strblobptr& operator--
strblobptr& strblobptr::operator++(
//如果curr已经指向容器尾后位置,则无法递增它。
check(curr,"increment past end of strblobptr");
++curr;
return *this;
strblobptr& strblobptr::operator--(
//如果curr是0,则继续递减它将产生一个无效下标。
--curr; /如果curr已经是0,那么我们传递个check的值将是一个表示无效下标的非常大的正整数。
check(curr , decrement past begin of strblobptr");
return *this;
为了区分前置和后置版本,后置版本接受一个额外的int类型的形参。只是为了区分前置和后置的函数。
class strblobptr{
public:
strblobptr operator++(int);
strblobptr operator--(int);
strblobptr strblobptr::operator++(
/ 此处无效检查有效性,调用前置递增运算时才需要检查。
strblobptr ret = this;
++*this;
return ret;
strblobptr strblobptr::operator--(int)
strblobptr ret = this;
C11学习笔记 5
参数传递时,如果是引用类型,它将绑定到对应的实参上,否者,将实参的值拷贝后赋给形参。引用可避免拷贝,如果不需要改变参数,最好定义成常量引用。和其他初始化一样,当用实参初始化时会忽略顶层const,当形参有顶层const时,传给它常量对象或非常量对象都可以。我们可以用非常量初始化一个底层const对象...
C 11学习笔记 11
动态分配的内存,只有在显式释放是,这些对象才会销毁。但是标准库中的两智能指针可以确保自动释放。除了静态内存和栈内存,每个程序还拥有一个内存池。这部分内存被称作自由空间或堆。静态内存用来保存局部static对象 类static数据成员以及定义在任何函数之外的变量。栈内存用来保存定义在函数没得非stat...
C 11学习笔记 16
tuple是类型pair的模板。不同tuple类型的成员类型也不同,但一个tuple可以有任意数量的成员。每个确定的tuple类型的成员数目是固定的。当我们希望将一些数据组合成单一对象,但有不想麻烦地定义一个新数据结构来表示时,tuple是非常有用的。快速而随意 的数据结构 tuple类型及其伴随类...