C++運算符重載 模板友元 new delete ++ = +=

 

今天的重載是基於C++ 類模板的,若是須要非類模板的重載的朋友能夠把類模板拿掉,一樣能夠參考,謝謝。ios

 

1、類模板中的友元重載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);
}

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

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

咱們去執行上述代碼的時候,編譯器就會報錯:一個沒法解析的外部指令。spa

固然,將實現放入聲明中是能夠的,可是爲了維護類的書寫風格,咱們仍是但願有一種方法能夠去維護這個風格。code

那麼咱們能夠將類中友元函數的聲明寫成以下形式:對象

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

 

緣由很簡單,類模板具備抽象性,而剛剛那個友元函數就是普通的函數,不具備模板的抽象性。blog

即便參數爲CLA<T> ...  仍是同樣,它表明的只不過是一個參數的類型,函數自己依舊是一個普通的 函數。

而上述的形式更像一個函數模板,將函數的模板實參同步於類模板的參數,這樣就能夠做爲類模板的友元了。

 

2、各類運算符重載

這部分咱們將會說到 +  -  *  /  關係運算符  賦值  自增自減   以及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個字節,沒有問題

 

類模板的運算符重載就到這裏了

感謝您的閱讀,祝您生活愉快!

相關文章
相關標籤/搜索