首页 > 代码库 > 0718-----C++Primer听课笔记----------运算符重载

0718-----C++Primer听课笔记----------运算符重载

0.两个要点

a) 一个空类,编译器自动合成默认无参构造函数、析构函数、拷贝构造函数、赋值运算符。

b) 在编写类的时候,必须严格区分对象是否可复制

1.运算符重载之 string类

1.1 运算符重载的几个要点:

a) 运算符重载可以有成员函数和友元函数的形式,后者比前者多一个参数。

b) =和+=必须重载为成员函数的形式(不太理解原因)

c) 输入和输出必须为友元函数的形式。而且输入操作符要考虑输入失败的情况。

d) 运算符重载为成员函数的形式,那么该操作符的第一个操作数必然为该类的对象。以+=为例,s += “hello” 那么等价于 s.operator+=(“hello”)。

1.2 String 类源码

#ifndef __STRING_H__#define __STRING_H__#include <stddef.h>#include <iostream>#include <string.h>class  String{    friend std::ostream &operator<<(std::ostream &, const String &);    friend std::istream &operator>>(std::istream &, String &);    friend String operator+(const String &, const String &);    friend String operator+(const String &, const char *);    friend String operator+(const char *, const String &);//    friend String &operator+(const char*, const char*);    friend bool operator==(const String &, const String &);    friend bool operator!=(const String &, const String &);    friend bool operator>(const String &, const String &);    friend bool operator<(const String &, const String &);    friend bool operator>=(const String &, const String &);    friend bool operator<=(const String &, const String &);    public:        String();        String(const char* str);        String(const String &other);        ~String();        String &operator= (const String &other);        String &operator= (const char *str);        String &operator+= (const String &other);        String &operator+= (const char *str);        char &operator[](size_t index);        char &operator[](size_t index) const;        size_t size() const;        void debug() const;    private:        char *str_;};inline std::ostream &operator<<(std::ostream &os, const String &s){    return os << s.str_; //将换行权交给调用者}inline std::istream &operator>>(std::istream &is, String &s){    char buf[1024];    is >> buf;    if(is){         //输入失败时不改变原对象        s.str_ = buf;    }    return is;}inline String operator+(const String &s1, const String &s2){    String ret(s1); //加法不改变原对象    ret += s2;    return ret;}inline String operator+(const String &s1, const char *s2){    return s1 + String(s2);}inline String operator+(const char *s1, const String &s2){    return String(s1) + s2;}inline bool operator==(const String &s1, const String &s2){    return ::strcmp(s1.str_, s2.str_) == 0;}inline bool operator!=(const String &s1, const String &s2){    return  !(s1 == s2);}inline bool operator>(const String &s1, const String &s2){    return ::strcmp(s1.str_, s2.str_) > 0;}inline bool operator<(const String &s1, const String &s2){    return  s2 > s1;}inline bool operator>=(const String &s1, const String &s2){    return !(s1 < s2);}inline bool operator<=(const String &s1, const String &s2){    return !(s1 > s2);}#endif#include "string.h"#include <iostream>#include <string.h>String::String()    :str_ (new char[1]){     str_[0] = 0;}String::String(const char* str)    :str_(new char[::strlen(str) + 1]){    ::strcpy(str_, str);}String::String(const String &other)    :str_(new char[::strlen(other.str_) + 1]){   :: strcpy(str_, other.str_);}String::~String(){    delete[] str_;}String& String::operator=(const String &other){    if(&other != this){        delete[] str_;        str_ = new char[::strlen(other.str_) + 1];        ::strcpy(str_, other.str_);    }    return *this;}String &String::operator=(const char *str){    return operator=(String(str));}String &String::operator+=(const String &other){    char *ret = new char[size() + other.size() + 1];    ret = str_;    ::strcat(ret, other.str_);    str_ = ret;    return *this;}String &String::operator+=(const char *str){    return operator+=(String(str));}char &String::operator[](size_t index){    return str_[index];}char &String::operator[](size_t index) const{    return str_[index];}size_t String::size() const{    return ::strlen(str_);}void String::debug()const{    std::cout << str_ << std::endl;}#include "string.h"#include <iostream>using namespace std;int main(int argc, const char *argv[]){    String s1("apple");   // cout << s1 << endl;    String s3;    s3 = "hello";    //cout << "world " + s3 << endl;    cout << (s1 == s3) << endl;    cout << (s1 > s3) <<endl;    cout << (s1 >= s3) << endl;    return 0;}
 

2.  自增运算符的重载

2.1 以整形 Integer 类为例,来重载前缀自增运算符(++i)和 后缀自增运算符(i++),这里要注意的几点:

a) 为了区别两个函数,我们将前缀自增运算符的重载函数中增加一个无用的参数。

b) 重载输出操作符的第二个参数 必须是 const, 因为在调用 i++ 时,函数返回值采用值传递,生成了临时对象,注意临时对象是不能修改的 具有const语义,因而此处必须设为const;对于++i 操作 ,该函数返回当前对象的引用,因而是否为const不影响。因此要记住,重载输出操作符时,第二个参数都设为const 引用,这里第一个参数也必须是引用,因为流对象不能复制和赋值。

c) 在生成临时对象的时候调用了拷贝构造函数。

d) Integer(int data)类型的构造函数,具有一种转化语义,能够将int转化为Integer,而加上explicit就禁用掉了转化语义。加上该关键字后,只能采用原生的构造方式如Integer t(100),而不能使用转化形式Integer t = 33。

e)自增操作符,前置和后置的区别:前置直接修改原对象,直接返回; 后置需要暂存之前的结果,修改对象后,将旧的对象返回。

 

2.2 源码

#ifndef __INTEGER_H__#define __INTEGER_H__#include <iostream>class Integer{    friend  std::ostream &operator<<(std::ostream &os, const Integer &itg);    public:        Integer();        explicit Integer(int data);        Integer(const Integer &other);        ~Integer();        Integer &operator=(const Integer &i);        /*         * 为了区别前缀和后缀式 传入一个无用的形参         */        Integer &operator++();        Integer operator++(int);    private:        int data_;};inline std::ostream &operator<<(std::ostream &os, const Integer &itg){    return os << itg.data_;}#endif#include "integer.h"Integer::Integer()    :data_(0){}Integer::Integer(int data)    :data_(data){}Integer::Integer(const Integer &other)    :data_(other.data_){    std::cout << "call copy construction" << std::endl;}Integer::~Integer(){}Integer &Integer::operator=(const Integer &i){    data_ = i.data_;    return *this;}Integer &Integer::operator++(){    std::cout << "call prefix " << std::endl;    data_++;    return *this;}Integer Integer::operator++(int){//此处的 int无用 因此不用命名    std::cout << "call postfix" << std::endl;    Integer ret(*this);    data_++;    return ret; //这里函数返回时 生成了临时对象;}#include <iostream>#include "integer.h"using namespace std;int main(int argc, const char *argv[]){    Integer itg(10);    cout << itg << endl;    cout << ++itg << endl;    Integer itg2(20);    cout << itg2 << endl;    cout << itg2++ << endl;/* * 构造函数加上 explicit 之后 * 再使用这种隐身转换就会报错    Integer itg3 = 8;    cout << itg3 << endl;*/    return 0;}