• 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;
    }
  • 相关阅读:
    DevExpress RichEditControl 上下翻页功能 z
    DockManager 如何快速隐藏DockPanel z
    DevExpress SpreadSheet报表模板设置 z
    DocumentManager在标签位置显示气泡框 z
    C#,数据类型扩展 z
    [安卓] 6、列表之ArrayAdapter适配
    [安卓] 5、SeekBar拖动条
    [安卓] 4、CheckBox、RadioButton和Toast简单用法
    [安卓] 3、EditText使用小程序
    [安卓] 2、使用2中方法做按钮监听和图片按钮使用
  • 原文地址:https://www.cnblogs.com/monicalee/p/3855023.html
Copyright © 2020-2023  润新知