1.基本概念

    当运算符被用于类类型对象时,C++语言允许我们为其指定新的含义,同时,我们也可以自定义类类型之间的转换规则。

    以下是运算符重载时需要注意的几个原则:

  • 当运算符作用于内置类型对象时,我们无法改变该运算符的含义
  • 我们只能重载已存在的运算符,不能发明新的运算符
  • 重载的运算符的优先级和结合律与对应的内置运算符保持一致
  • 以下运算符不能被重载:  
::    .*    .    ? :
  • 应使用与内置类型一致的含义

    关于选择重载运算符函数作为成员还是非成员函数:

  • 赋值(=)、下标( [ ] )、调用( ( ) )和成员访问箭头( -> )必须是成员
  • 复合赋值运算符(+=之类)一般来说应该是成员
  • 改变对象状态的运算符或者与给定类型密切相关的运算符,入递增、递减和解引用运算符,通常应该是成员
  • 具有对称性的运算符可能转换任意一端的运算对象,例如算术、相等性、关系和位运算符等,通常应是非成员函数

下面以String为例演示重载各个运算符的用法。

2.输入和输出运算符

//输入输出函数只能是非成员函数,故要在类内声明为友元函数
friend std::ostream &operator<<(std::ostream &os, const String &s);
friend std::istream &operator>>(std::istream &is, String &s); 
/*输出函数较为简单,需要注意的是,第一个形参要设置为非常量,
因为向流中写入会改变流的状态。返回值是形参中的ostream对象,
原因是要实现连续输出。*/
std::ostream &operator<<(std::ostream &os, const String &s){
    os << s._pstr;
    return os;
}

/*输入函数较为复杂,因为输入时无法确定输入的字符串长度,
所以此处使用了vector存储为字符数组,再根据字符数组的长度
开辟堆空间存储字符串*/
std::istream &operator>>(std::istream &is, String &s){
    /*由于输入长度未知,故需要用vector存储*/
    delete [] s._pstr;
    std::vector<char> newString;
    char ch;
    while( (ch = is.get()) != '\n' ){
        newString.push_back(ch);
    }
    /*执行输入运算符时可能会发生错误,故需要检查是否输入正确,
若不正确,则vector中没有数据,不能将vector中的数据复制到string中*/
    if(is)
        strcpy(s._pstr, &newString[0]);
    /*若发生错误前对string对象的内容有改动,则需要将对象置为合法状态
,具体见《C++ Primer》14.2.2节。
    else
        s = String();
    */
    return is;
} 

3.算术和关系运算符

    

08-12 05:19