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个字节,没有问题

     

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

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

  • 相关阅读:
    HDU 2116 Has the sum exceeded
    HDU 1233 还是畅通工程
    HDU 1234 开门人和关门人
    HDU 1283 最简单的计算机
    HDU 2552 三足鼎立
    HDU 1202 The calculation of GPA
    HDU 1248 寒冰王座
    HDU 1863 畅通工程
    HDU 1879 继续畅通工程
    颜色对话框CColorDialog,字体对话框CFontDialog使用实例
  • 原文地址:https://www.cnblogs.com/lv-anchoret/p/8342842.html
Copyright © 2011-2022 走看看