C++运算符重载

C++运算符重载

C++运算符重载:使对象的运算表现得和编译器内置类型一样

C++实现复数类实现运算符重载

C++类对象操作符重载函数函数时,会优先调用类的成员方法,没有找到再去全局去寻找对应的方法

在调用某些操作符重载函数时,如果类型不满足条件可以进行产生临时对象,然后再进行操作符重载。

++/-- 表示自增运算符,也称为单目运算符 i++,++i怎么进行区分呢。C++中将前置++i,利用operator++()表示;后置i++,利用operator++(int)表示;这样就构成了函数重载,实现了i++和++i分离。

#include<iostream>
using namespace std;
class Complex
{
public:
    Complex(int r = 0, int i = 0) : mreal(r), mimage(i) { cout << "Complex(int,int)" << endl; }
    Complex(const Complex &src) { cout << "Complex(const Complex&)" << endl; }
    // 这里不能将Complex替换为Complex&,因为这里返回的对象是局部的,出了作用域就会被析构了
    Complex operator+(const Complex &src)
    {
        cout << "Complex operator+(const Complex &src)" << endl;
        // method 1 这里会产生一个对象,到时候会在调用这个函数的时候产生一个临时对象
        /*
        Complex comp;
        comp.mreal = this->mreal + src.mreal;
        comp.mimage = this->mimage + src.mimage;
        return comp;
        */
        // method 2 直接在调用这个函数的栈上生成临时对象,就不会在这里产生一个对象
        return Complex(this->mreal + src.mreal, this->mimage + src.mimage);
    }
    ~Complex() { cout << "~Complex()" << endl; }
    void show()
    {
        cout << "mreal:" << mreal << " mimage:" << mimage << endl;
    }
    // ++i前置++
    Complex& operator++()
    {
        mreal += 1;
        mimage += 1;
        return *this;
    }
    // i++后置++
    Complex operator++(int)
    {
        // Complex c = *this;
        // mreal += 1;
        // mimage += 1;
        // return *this;
        return Complex(mreal++, mimage++);
    }
    void operator+=(const Complex& src)
    {
        mreal += src.mreal;
        mimage = src.mimage;
    }

private:
    int mreal;
    int mimage;
    friend Complex operator+(const Complex &src1, const Complex &src2);//声明成友元函数就可以访问私有属性
    friend ostream &operator<<(ostream &out, const Complex &src);
    friend istream &operator>>(istream &in, Complex &src);
};

Complex operator+(const Complex& src1,const Complex& src2)
{
    cout << "Complex operator+(const Complex& src1,const Complex& src2)" << endl;
    return Complex(src1.mreal + src2.mreal, src1.mimage + src2.mimage);
}

ostream& operator<<(ostream& out,const Complex& src)
{
    out << "mreal:" << src.mreal << " mimage:" << src.mimage << endl;
    return out;
}
istream& operator>>(istream& in,Complex& src)
{
    in >> src.mreal >> src.mimage;
    return in;
}

int main()
{
    Complex c1(10, 10);
    Complex c2(20, 20);
    cout << "-----------" << endl;
    Complex c3 = c1 + c2;//c1+c2等价于c1.operator+(c2),所以+操作符重载只有一个参数
    cout << "-----------" << endl;
    c3.show();
    Complex c4 = c3 + 20;//这里会将20进行转化成Complex类,调用构造函数
    c4.show();
    
    // 编译器做对象运算的时候,会调用对象的运算符重载函数(优先调用成员方法)
    // 如果没有成员方法,就在全局作用域找合适的运算符重载函数
    // Complex c5 = 30 + c4;//如果没有定义全局函数,这里会转化错误,没有办法将30转化为Complex
    Complex c5 = 30 + c4;//定义了全局的operator+后就能调用::operator+(30,c4);
    c5.show();
    c5++;
    c5.show();

    cout << c5;
    /*
    ++/-- 表示自增运算符,也称为单目运算符  i++,++i怎么进行区分呢
    C++中将前置++i,利用operator++()表示;后置i++,利用operator++(int)表示;
    这样就构成了函数重载,实现了i++和++i分离
    */
    cin >> c5;
    cout << c5;
    return 0;
}

这里其实存在一个细节点,可以用于节省资源,如下代码所示:

Complex& operator++()
{
     mreal += 1;
     mimage += 1;
     return *this;
 }
 // i++后置++
 Complex operator++(int)
 {
     // Complex c = *this;
     // mreal += 1;
     // mimage += 1;
     // return *this;
     return Complex(mreal++, mimage++);
 }

可以看到前置运算符++返回的是引用,而后置++返回的是一个新对象,所以一般没有区别的时候尽量使用前置++的操作符运算,这样就会节省对象的创建和析构。

C++自定义实现String

String内部实现最复杂的是operator+()操作符重载,涉及了堆内存的开辟和释放问题。

#include<iostream>
#include<string.h>

using namespace std;

class String
{
public:
    String(const char* p=nullptr)
    {
        if(p!=nullptr)
        {
            _pstr = new char[strlen(p) + 1];
            strcpy(_pstr, p);
        }
        else
        {
            _pstr = new char[1];
            *_pstr = '\0';
        }
    }
    ~String()
    {
        delete[] _pstr;
        _pstr = nullptr;
    }
    String(const String& src)
    {
        _pstr = new char[strlen(src._pstr) + 1];
        strcpy(_pstr, src._pstr);
    }
    String& operator=(const String& src)
    {
        if(this==&src)
            return *this;
        delete[] _pstr;
        _pstr = new char[strlen(src._pstr) + 1];
        strcpy(_pstr, src._pstr);
        return *this;
    }
    bool operator>(const String &src) const
    {
        return strcmp(_pstr, src._pstr) > 0;
    }
    bool operator==(const String &src) const
    {
        return strcmp(_pstr, src._pstr) == 0;
    }
    bool operator<(const String &src) const
    {
        return strcmp(_pstr, src._pstr) < 0;
    }
    int length()const
    {
        return strlen(_pstr);
    }
    char &operator[](int index) { return _pstr[index]; }
    const char &operator[](int index) const { return _pstr[index]; }
    const char *c_str() const { return _pstr; }
    
private:
    char *_pstr;
    friend String operator+(const String &lsrc, const String &rsrc);
    friend ostream &operator<<(ostream &out, const String &src);
    friend istream &operator>>(istream &in, String &src);
};

String operator+(const String &lsrc,const String &rsrc)
{
    // char *temp = new char[strlen(lsrc._pstr) + strlen(rsrc._pstr) + 1];
    // strcpy(temp, lsrc._pstr);
    // strcat(temp, rsrc._pstr);
    // String s(temp);
    // delete[] temp;
    String s;
    s._pstr = new char[strlen(lsrc._pstr) + strlen(rsrc._pstr) + 1];
    strcpy(s._pstr, lsrc._pstr);
    strcat(s._pstr, rsrc._pstr);
    return s;
}
ostream& operator<<(ostream& out,const String& src)
{
    out << src._pstr;
    return out;
}
istream &operator>>(istream &in, String &src)
{
    in >> src._pstr;
    return in;
}

int main()
{
    String str1;
    String str2 = "aaa";
    String str3 = "bbb";
    String str4 = str2 + str3;
    String str5 = str2 + "ccc";
    String str6 = "ddd" + str2;

    cout << "str6:" << str6 << endl;
    if(str5>str6)
    {
        cout << str5 << ">" << str6 << endl;
    }
    else
    {
        cout << str5 << "<" << str6 << endl;
    }
    int len = str6.length();
    for (int i = 0; i < len;i++)
    {
        cout << str6[i] << " ";
    }
    cout << endl;

    char buf[1024] = {0};
    strcpy(buf, str6.c_str());
    cout << "buf:" << buf << endl;

    return 0;
}

迭代器(iterator)是C++容器的一大特性,迭代器可以透明的访问容器内部元素的值(不用知道容器底层的数据结构,数组,链表等)。

泛型算法参数接收的都是迭代器。

泛型算法-全局的函数-给所有的容器使用的。

泛型算法,有一套方式,能够统一的遍历所有的容器内部的元素-迭代器。

实现String容器的迭代器:

#include<iostream>
#include<string.h>

using namespace std;

class String
{
public:
    String(const char* p=nullptr)
    {
        if(p!=nullptr)
        {
            _pstr = new char[strlen(p) + 1];
            strcpy(_pstr, p);
        }
        else
        {
            _pstr = new char[1];
            *_pstr = '\0';
        }
    }
    ~String()
    {
        delete[] _pstr;
        _pstr = nullptr;
    }
    String(const String& src)
    {
        _pstr = new char[strlen(src._pstr) + 1];
        strcpy(_pstr, src._pstr);
    }
    String& operator=(const String& src)
    {
        if(this==&src)
            return *this;
        delete[] _pstr;
        _pstr = new char[strlen(src._pstr) + 1];
        strcpy(_pstr, src._pstr);
        return *this;
    }
    bool operator>(const String &src) const
    {
        return strcmp(_pstr, src._pstr) > 0;
    }
    bool operator==(const String &src) const
    {
        return strcmp(_pstr, src._pstr) == 0;
    }
    bool operator<(const String &src) const
    {
        return strcmp(_pstr, src._pstr) < 0;
    }
    int length()const
    {
        return strlen(_pstr);
    }
    char &operator[](int index) { return _pstr[index]; }
    const char &operator[](int index) const { return _pstr[index]; }
    const char *c_str() const { return _pstr; }
    
    class iterator
    {
    public:
        iterator(char *p = nullptr) : _p(p){}
        void operator++()
        {
            ++_p;
        }
        bool operator!=(const iterator& src)
        {
            if(_p!=src._p)
                return true;
            return false;
        }
        char& operator*()
        {
            return *_p;
        }

    private:
        char* _p;
    };
    iterator begin() { return iterator(_pstr); };
    iterator end() { return iterator(_pstr + length()); }

private:
    char *_pstr;
    friend String operator+(const String &lsrc, const String &rsrc);
    friend ostream &operator<<(ostream &out, const String &src);
    friend istream &operator>>(istream &in, String &src);
};

String operator+(const String &lsrc,const String &rsrc)
{
    String s;
    s._pstr = new char[strlen(lsrc._pstr) + strlen(rsrc._pstr) + 1];
    strcpy(s._pstr, lsrc._pstr);
    strcat(s._pstr, rsrc._pstr);
    return s;
}
ostream& operator<<(ostream& out,const String& src)
{
    out << src._pstr;
    return out;
}
istream &operator>>(istream &in, String &src)
{
    in >> src._pstr;
    return in;
}

int main()
{
    String a = "ababas";
    // 迭代器的作用:提供统一的形式,来遍历容器
    String::iterator it = a.begin();
    for (; it != a.end();++it)
    {
        cout << *it << " ";
    }
    return 0;
}

C++实现vector(包含迭代器)

在原先的内容基础上添加了迭代器部分,Vector实现了元素内存开辟和对象创建的分离,当然内存回收和对象析构也进行了分离。

#include <iostream>
using namespace std;

template <typename T>
class Allocator
{
public:
    T *allocator(size_t size) // 负责内存开辟,size个数量
    {
        return (T *)malloc(sizeof(T) * size);
    }
    void deallocator(T *p) // 内存释放
    {
        free(p);
    }
    void construct(T *p, const T &val) // 对象创建
    {
        // 更多new初始化方法 https://blog.csdn.net/qq_45041871/article/details/132251733
        new (p) T(val); // 使用的是定位new,将val传到地址为p的空间去,p地址指向val
    }
    void destroy(T *p) // 对象析构
    {
        p->~T();
    }
};
template <typename T, typename Alloc = Allocator<T>>
class Vector
{
public:
    Vector(int size = 5)
    {
        // 需要将内存开辟和对象构造分开处理
        // _first = new T[size];
        _first = _allocator.allocator(size); // 只开辟空间
        _last = _first;
        _end = _first + size; // 这就相当于指针遍历移动
    }
    ~Vector()
    {
        // 析构容器中有效的元素,然后释放_first指针所指向的内存
        // delete[] _first;
        for (T *p = _first; p != _last; ++p)
        {
            _allocator.destroy(p);
        }
        _allocator.deallocator(_first);
        _first = _last = _end = nullptr;
    }
    Vector(const Vector<T> &src)
    {
        int size = src._end - src._first;
        // _first = new T[size];
        _first = _allocator.allocator(size);
        for (int i = 0; i < src._last - src._first; i++)
        {
            // _first[i] = src._first[i];
            _allocator.construct(_first + i, src._first[i]);
        }
        _last = _first + src._last - src._first;
        _end = _first + size;
    }
    Vector<T> &operator=(const Vector<T> &src)
    {
        if (this == &src)
            return *this;
        // delete[] _first;
        for (T *p = _first; p != _last; p++)
        {
            _allocator.destroy(p);
        }
        _allocator.deallocator(_first);

        int size = src._end - src._first;
        _first = new T[size];
        for (int i = 0; i < src._last - src._first; i++)
        {
            // _first[i] = src._first[i];
            _allocator.construct(_first + i, src._first[i]);
        }
        _last = _first + src._last - src._first;
        _end = _first + size;
        return *this;
    }
    void push_back(T &val)
    {
        if (full())
            expand();
        _allocator.construct(_last, val);
        _last++;
    }
    void pop_back()
    {
        if (empty())
            return;
        _last--;
        _allocator.destroy(_last);
    }
    T back() const
    {
        return *(_last - 1);
    }
    bool full() const { return _last == _end; }
    bool empty() const { return _last == _first; }
    int size() { return _last - _first; }
    T& operator[](int index)
    {
        if(index<0||index>size())
            throw "OutOfRangeException";
        return _first[index];
    }

    class iterator
    {
    public:
        iterator(T *ptr=nullptr):_ptr(ptr){}
        bool operator!=(const iterator &it) const{ return it._ptr != _ptr;}
        void operator++() { ++_ptr; }
        T &operator*() { return *_ptr; }
        const T &operator*() const { return *_ptr; }

    private:
        T *_ptr;
    };

    iterator begin() { return iterator(_first); }
    iterator end() { return iterator(_last); }

private:
    T *_first; // 指向数组起始的位置
    T *_last;  // 指向数组中有效元素的后继位置
    T *_end;   // 指向数组空间的后继位置

    iterator _iterator;
    Alloc _allocator; // 定义容器的空间配置器
    void expand()
    {
        int size = _end - _first;
        // T *temp = new T[size * 2];
        T *temp = _allocator.allocator(size * 2);
        for (int i = 0; i < size; i++)
        {
            // temp[i] = _first[i];
            _allocator.construct(temp + i, _first[i]);
        }
        // delete[] _first;
        for (T *p = _first; p != _last; p++)
        {
            _allocator.destroy(p);
        }
        _allocator.deallocator(_first);

        _first = temp;
        _last = _first + size;
        _end = _last + size;
    }
};
int main()
{
    Vector<int> v;
    for (int i = 0; i < 20;i++)
    {
        v.push_back(i);
    }
    int size = v.size();
    for (int i = 0; i < size;i++)
    {
        cout << v[i] << " ";
    }
    cout << endl;

    Vector<int>::iterator it = v.begin();
    for (; it != v.end();++it)
    {
        cout << *it << " ";
    }
    cout<<endl;

    return 0;
}

iterator失效问题

迭代器失效问题?

1、迭代器为什么会失效?

  • 当容器调用erase方法后,当前位置到容器末尾元素的所有的迭代器全部失效了。
  • 当容器调用insert方法后,当前位置到容器末尾元素的所有的迭代器全部失效了。

迭代器情况:

首元素 -> 插入点/删除点 -> 末尾元素


原始的vector容器中的迭代器是怎么解决这个问题的呢?

通过迭代器erase和insert函数返回当前迭代器的情况进行处理。

如下代码所示:

#include<iostream>
#include<vector>
using namespace std;

int main()
{
    vector<int> vec;
    for (int i = 0; i < 20; ++i)
    {
        vec.push_back(rand() % 100 + 1);
    }
    vector<int>::iterator it = vec.begin();

#if 0
    //给vec容器中所有偶数前面添加一个小于偶数值1的数字
    for (; it != vec.end(); ++it)
    {
        if (*it % 2 == 0)
        {
            //这里会产生迭代器失效问题,第一次调用insert之后,iterator就失效了
            vec.insert(it, *it - 1);//在当前迭代器it上插入值为val,如果没有break就会出现问题,程序会崩溃
        }
    }
    //把容器vec容器的偶数全部删除
    for (; it != vec.end(); ++it)
    {
        if (*it % 2 == 0)
        {
            //这里会产生迭代器失效的问题,第一次调用了erase函数之后,迭代器it就会失效
            vec.erase(it);//erase删除当前的位置的迭代器,这里如果没有break就会出现问题
        }
    }
#endif
    for (; it != vec.end(); ++it)
    {
        if (*it % 2 == 0)
        {
            it=vec.insert(it, *it - 1);//插入一个新元素后,迭代器就会指向该元素,并把之前指向的往后移
            it++;
        }
    }
    for (; it != vec.end();)
    {
        if (*it % 2 == 0)
        {
            it=vec.erase(it);//如果删除了当前迭代器,那么就会将下一个元素的迭代器返回回来
        }
        else
        {
            ++it;
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Trouble..

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值