zoukankan      html  css  js  c++  java
  • C++运算符重载 模板友元 new delete ++ = +=

    今天的重载是基于C++ 类模板的,如果需要非类模板的重载的朋友可以把类模板拿掉,同样可以参考,谢谢。

    一、类模板中的友元重载

    本人喜好类声明与类成员实现分开写的代码风格,如若您喜欢将类成员函数的实现写在类声明中,那么可以跳过该部分。

    请看下面这段代码:  

    头文件:

    #pragma once
    template<typename T>
    class  CLA
    {
        T m_value;
    public:
        CLA(const T&);
        friend CLA operator+(const CLA&, const CLA&); 
    };
    template<typename T>
    CLA<T>::CLA(const T& a)
        :m_value(a)
    { }
    
    template<typename T>
    CLA<T> operator+(const CLA<T>& lhs, const CLA<T>& rhs)
    {
        return CLA<T>(lhs.m_value + rhs.m_value);
    }

    源文件:(已包含上述的头文件)

    int main()
    {
        CLA<int> a{ 0 }, b{ 1 }, c{ 2 };
        a + b;
        return 0;
    }

    我们去执行上述代码的时候,编译器就会报错:一个无法解析的外部指令。

    当然,将实现放入声明中是可以的,但是为了维护类的书写风格,我们还是希望有一种方法可以去维护这个风格。

    那么我们可以将类中友元函数的声明写成如下形式:

    friend CLA operator+<T>(const CLA&, const CLA&); 

     

    原因很简单,类模板具有抽象性,而刚刚那个友元函数就是普通的函数,不具有模板的抽象性。

    即使参数为CLA<T> ...  还是一样,它代表的只不过是一个参数的类型,函数本身依旧是一个普通的 函数。

    而上述的形式更像一个函数模板,将函数的模板实参同步于类模板的参数,这样就可以作为类模板的友元了。

    二、各种运算符重载

    这部分我们将会说到 +  -  *  /  关系运算符  赋值  自增自减   以及new   delete 的重载。

     

     首先,几个简单的 + - * /  友元以及非友元重载形式 

    #pragma once
    #include<iostream>
    using namespace std;
    
    template<typename T>
    class  CLA
    {
        T m_value;
    public:
        CLA():m_value(0){}
        CLA(const T&);
        CLA(const CLA&);
        //友元形式
        friend CLA operator+<T>(const CLA&, const CLA&);   //同类型
        friend CLA operator+<T>(const CLA&, const T);      //不同类型
        friend CLA operator-<T>(const CLA&, const CLA&);   //同类型
        friend CLA operator-<T>(const CLA&, const T);      //不同类型
        //非友元形式
        CLA operator*(const CLA&);               //同类型
        CLA operator*(const T);                  //不同类型
        CLA operator/(const CLA&);               //同类型
        CLA operator/(const T);                  //不同类型
    };
    template<typename T>
    CLA<T>::CLA(const T& a)
        :m_value(a)
    { }
    template<typename T>
    CLA<T> operator+(const CLA<T>& lhs, const CLA<T>& rhs)
    {
        return CLA<T>(lhs.m_value + rhs.m_value);
    }
    template<typename T>
    CLA<T> operator+(const CLA<T>& lhs, const T  rhs)
    {
        return CLA<T>(lhs.m_value + rhs);
    }
    template<typename T>
    CLA<T>::CLA(const CLA<T>& rhs)
        : m_value(rhs.m_value)
    { }
    
    template<typename T>
    CLA<T> operator-(const CLA<T>& lhs, const CLA<T>& rhs)
    {
        return CLA<T>(lhs.m_value - rhs.m_value);
    }
    template<typename T>
    CLA<T> operator-(const CLA<T>& lhs, const T rhs)
    {
        return CLA<T>(lhs.m_value - rhs);
    }
    template<typename T>
    CLA<T> CLA<T>::operator*(const CLA<T>& rhs)
    {
        return CLA<T>(m_value * rhs.m_value);
    }
    template<typename T>
    CLA<T> CLA<T>::operator*(const T rhs)
    {
        return CLA<T>(m_value * rhs);
    }
    template<typename T>
    CLA<T> CLA<T>::operator/(const CLA<T>& rhs)
    {
        if (rhs.m_value)
            return CLA<T>(m_value / rhs.m_value);
        else
            cout << "非法除法!" << endl;
        return CLA<T>();
    }
    template<typename T>
    CLA<T> CLA<T>::operator/(const T rhs)
    {
        if (rhs)
            return CLA<T>(lhs.m_value / rhs);
        else
            cout << "非法除法!" << endl;
        return CLA<T>();
    }

     接下来重载输入输出流,而且必须为友元才行

    friend istream& operator>> <T>(istream&, CLA&);
    friend ostream& operator<< <T>(ostream&, const CLA&);
    istream& operator>>(istream& is, CLA<T>& rhs)
    {
        is >> rhs.m_value;
        return is;
    }
    template<typename T>
    ostream& operator<<(ostream& os, const CLA<T>& rhs)
    {
        os << rhs.m_value;
        return os;
    }

    输入流重载的第二个参数不能为const,因为在函数体中要对之进行修改

     

    然后,我们用下面的代码来看一下测试结果:

    int main()
    {
        CLA<int> a{ 0 }, b{ 1 }, c{ 2 };
        CLA<char>  B{ 'b' };
        b / a;                             //相同类型
        cout << b*c << endl;               //相同类型
        cout << B + (char)1 << endl;       //不同类型的
        cout << B - (char)1 << endl;       //不同类型的
    return 0;
    }

     没有问题

     

    接下类重载一些赋值运算符,=  +=  -=

    CLA& operator=(const CLA&);
    CLA& operator+=(const CLA&);
    CLA& operator-=(const CLA&);
    CLA<T>& CLA<T>::operator=(const CLA<T>& rhs)
    {
        if (this != &rhs)
            m_value = rhs.m_value;
        return *this;
    }
    template<typename T>
    CLA<T>& CLA<T>::operator+=(const CLA<T>& rhs)
    {
        m_value += rhs.m_value;
        return *this;
    }
    template<typename T>
    CLA<T>& CLA<T>::operator-=(const CLA<T>& rhs)
    {
        m_value -= rhs.m_value;
        return *this;
    }

    赋值号要记得要有判同语句,运算完成后要将*this,也就是操作符的左操作数,返回。

    这部分之后进行测试

     

    ++重载(--雷同)

    CLA& operator++();          //前++
    const CLA operator++(int);  //后++
    CLA<T>& CLA<T>::operator++()
    {
        ++m_value;
        return *this;
    }
    template<typename T>
    const CLA<T> CLA<T>::operator++(int)              //语法规定,在后++函数的参数中加int以作区分
    {
        CLA<T> item(m_value);
        ++m_value;
        return item;
    }

    根据前++和后++的语法规则,前++,将本身的值+1,然后再将其本身返回。如上述操作函数体语句所示。

    而后++则是将原值返回,然后本身+1,所以,我们需要借助一个局部变量来保存原值,而且返回之后是不允许改变的,代表一个常量,所以返回值拥有const属性

     

    关系运算符也挺简单的

    friend bool operator!= <T>(const CLA&, const CLA&);//友元
    bool operator!=(const CLA&);                       //成员函数
    bool operator==(const CLA&);
    bool operator<(const CLA&);
    bool operator>=(const CLA&);
    template<typename T>
    bool operator!=(const CLA<T>& lhs, const CLA<T>& rhs)
    {
        return lhs.m_value != rhs.m_value;
    }
    bool CLA<T>::operator!=(const CLA<T> & rhs)
    {
        return this->m_value != rhs.m_value;
    }
    template<typename T>
    bool CLA<T>::operator==(const CLA<T>& rhs)
    {
        return m_value == rhs.m_value;
    }
    template<typename T>
    bool CLA<T>::operator<(const CLA<T>& rhs)
    {
        return m_value < rhs.m_value;
    }
    template<typename T>
    bool CLA<T>::operator>=(const CLA<T>& rhs)
    {
        return m_value > rhs.m_value;
    }

     

     我们来测试一下

    int main()
    {
        
        CLA<int> a{ 0 }, b{ 1 }, c{ 2 };
        if (a != b)
            cout << "a!=b" << endl;
        a++;
        if (a == b)
            cout << "a==b" << endl;
    
        //c++++             //Invalid !!
        CLA<int> r = ++++a;
        cout << r << endl;
        cout << (r += 1) << endl;
        cout << (r < a) << endl;
    
            return 0;
    }

    忘了写连续赋值,不过,经测试也是可以的,没问题 。

     

    那么,现在我们来重载  new  和delete 以及new [ ] 和 delete [ ]

    void* operator new(size_t size); 
    void* operator new[](size_t size);
    void operator delete(void* p);
    void operator delete[](void* p);

    这里我们要用到的一个C语言库里面的类型—— size_t,它是unsigned int,sizeof运算符算出来的值就是它喽,在这里作为参数,它会自动计算大小,很方便

    那,我们来看一下它的实现:

    template<typename T>
    void* CLA<T>::operator new(size_t size)
    {
        cout << size << endl;
        cout << "调用了new" << endl;
        return malloc(size);
    }
    template<typename T>
    void* CLA<T>::operator new[](size_t size)
    {
        cout << size << endl;
        cout << "调用了new[]" << endl;
        return malloc(size);
    }
    template<typename T>
    void CLA<T>::operator delete(void* p)
    {
        free(p);
        cout << "调用了delete函数" << endl;
    }
    template<typename T>
    void CLA<T>::operator delete[](void* p)
    {
        free(p);
        cout << "调用了delete[]函数" << endl;
    }

    我们写一些对应的输出来帮助我们确定一些信息。

    int main()
    {
        CLA<int>* w = new CLA<int>(10);
        delete  w;
        CLA<int>* W = new CLA<int>[10];
        delete[] W;
        return 0;
    }

    第一个10为创建的对象的值,第二个为开辟的数组的大小

    一个int为4个字节,开辟10个大小的内存,为40个字节,没有问题

     

    类模板的运算符重载就到这里了

    感谢您的阅读,祝您生活愉快!

  • 相关阅读:
    Linux常用解压文件
    微信开放平台 获取 component_verify_ticket
    mysql root密码重置
    编译安装LNMP
    JS生成二维码
    CURL采集
    JS拖动浮动DIV
    JS拖动DIV布局
    Nginx 反向代理、负载均衡、页面缓存、URL重写及读写分离详解
    zepto.js 源码注释备份
  • 原文地址:https://www.cnblogs.com/lv-anchoret/p/8342842.html
Copyright © 2011-2022 走看看