類模板 友元重載形式 各種運算符重載 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個字節,沒有問題
類模板的運算符重載就到這裏了,謝謝您的閱讀,祝您生活愉快!
類模板 友元重載形式 各種運算符重載 new delete ++ = +=