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;
}
原文地址:https://www.cnblogs.com/monicalee/p/3855023.html