文章目錄
- 一、支持 數組類模板 存儲的 自定義類
- 1、可拷貝和可打印的自定義類
- 2、改進方向
- 3、改進方向 - 構造函數
- 4、改進方向 - 析構函數
- 5、改進方向 - 重載左移運算符
- 6、改進方向 - 重載拷貝構造函數 和 等號運算符
- 二、代碼示例
- 1、Array.h 頭文件
- 2、Array.cpp 代碼文件
- 3、Test.cpp 主函數代碼文件
- 4、Test.cpp 主函數代碼文件
一、支持 數組類模板 存儲的 自定義類
1、可拷貝和可打印的自定義類
在上一篇博客 中 , 定義了 可拷貝 與 可打印 的 自定義類 Student , 可以被存放到 數組類模板 中 ;
由于其 成員變量 char m_name[32] 是 數組類型 , 創建時就直接分配了內存空間 , 即使淺拷貝也可以完成對 該類型對象的 拷貝工作 ;
class Student
{friend ostream& operator<<(ostream& out, const Student& s);
public:Student(){m_age = 10;strcpy(m_name, "NULL");}Student(const char* name, int age) {strcpy(this->m_name, name);this->m_age = age;}void printT() {cout << "name : " << m_name << " , age : " << m_age << endl;}private:char m_name[32];int m_age;
};// 重載左移運算符實現
ostream& operator<<(ostream& out, const Student& s) {out << "name : " << s.m_name << " , age : " << s.m_age << " ; ";return out;
}
2、改進方向
本篇博客中 , 開始討論 自定義類 中是 char* 類型指針的情況 , 這里涉及到了 堆內存分配 以及 深拷貝 問題 ;
如果將上述 Student 類中的 char m_name[32] 數組成員 , 改為 char* m_name 指針成員 ;
那么需要進行 堆內存管理 ,
- 在 構造函數中 分配堆內存 ;
- 在 析構函數中 釋放堆內存 ;
為了避免 淺拷貝 問題出現 , 需要
- 進行 等號 = 運算符重載 ;
- 以及 重寫 拷貝構造函數 ;
為了使用 cout 打印該 類對象 , 需要 進行 左移 << 運算符重載 ;
3、改進方向 - 構造函數
在類的 無參構造函數 和 有參構造函數中 ,
使用 new 關鍵字 , 自動在堆內存中分配內存 , 然后為 堆內存 中的空間賦值 ;
Student(){m_age = 10;// 創建一個數組個數為 1 的數組, 存放 '\0' 值// 這是一個空字符串m_name = new char[1];strcpy(m_name, "");}Student(const char* name, int age) {// 計算字符串大小// 總的大小是 字符個數 + \0 字符, 因此多一個字節int len = strlen(name) + 1;// 根據字符串大小創建 字符數組m_name = new char[len];strcpy(this->m_name, name);this->m_age = age;}
4、改進方向 - 析構函數
在析構函數中 , 需要將 使用 new 關鍵字申請的 堆內存進行釋放 , 這里必須使用 delete 進行釋放 ;
使用 malloc 申請的堆內存 , 必須使用 free 進行釋放 ;
使用 new 申請的堆內存 , 必須使用 delete 進行釋放 ;
~Student(){if (m_name != NULL){delete[] m_name;m_name = NULL;}}
5、改進方向 - 重載左移運算符
重載左移運算符 , 以便可以在 cout 中打印該類信息 ;
首先 , 在類內部聲明 重載左移運算符 的友元函數 ;
class Student
{friend ostream& operator<<(ostream& out, const Student& s);
}
然后 , 在 類外部 的 全局函數 中 , 實現 重載左移運算符函數 ;
// 重載左移運算符實現
ostream& operator<<(ostream& out, const Student& s) {out << "name : " << s.m_name << " , age : " << s.m_age << " ; ";return out;
}
6、改進方向 - 重載拷貝構造函數 和 等號運算符
重載拷貝構造函數 和 等號運算符 , 方便類初始化 和 使用等號賦值 ;
Student(const Student& s) {// 計算字符串大小// 總的大小是 字符個數 + \0 字符, 因此多一個字節int len = strlen(s.m_name) + 1;// 根據字符串大小創建 字符數組m_name = new char[len];strcpy(this->m_name, s.m_name);this->m_age = s.m_age;}// 重載等號操作符Student& operator=(const Student& obj) {if (m_name != NULL) {delete[] m_name;m_name = NULL;}// 計算字符個數int len = strlen(obj.m_name) + 1;// 根據字符串大小創建 字符數組m_name = new char[len];strcpy(this->m_name, obj.m_name);this->m_age = obj.m_age;return *this;}
二、代碼示例
1、Array.h 頭文件
#pragma once#include "iostream"
using namespace std;template <typename T>
class Array
{// 左移 << 操作符重載// 注意 聲明時 , 需要在 函數名 和 參數列表之間 注明 泛型類型 <T>// 實現時 , 不能在 函數名 和 參數列表之間 注明 泛型類型 <T>friend ostream& operator<< <T> (ostream& out, const Array& a);public:// 有參構造函數Array(int len = 0);// 拷貝構造函數Array(const Array& array);// 析構函數~Array();public:// 數組下標 [] 操作符重載// 數組元素類型是 T 類型T& operator[](int i);// 等號 = 操作符重載Array& operator=(const Array& a);private:// 數組長度int m_length;// 指向數組數據內存 的指針// 指針類型 是 泛型類型 TT* m_space;
};
2、Array.cpp 代碼文件
#include "Array.h"// 左移 << 操作符重載
// 注意 聲明時 , 需要在 函數名 和 參數列表之間 注明 泛型類型 <T>
// 實現時 , 不能在 函數名 和 參數列表之間 注明 泛型類型 <T>
template <typename T>
ostream& operator<< (ostream& out, const Array<T>& a)
{for (int i = 0; i < a.m_length; i++){// 在一行內輸入數據, 使用空格隔開, 不換行out << a.m_space[i] << " ";}// 換行out << endl;return out;
}// 有參構造函數
template <typename T>
Array<T>::Array(int len)
{// 設置數組長度m_length = len;// 為數組在堆內存中分配內存// 注意 元素類型為 Tm_space = new T[m_length];cout << " 調用有參構造函數 " << endl;
}// 拷貝構造函數
// 這是一個深拷貝 拷貝構造函數
template <typename T>
Array<T>::Array(const Array<T>& array)
{// 設置數組長度m_length = array.m_length;// 創建數組// 注意 元素類型為 Tm_space = new T[m_length];// 為數組賦值for (int i = 0; i < m_length; i++){m_space[i] = array.m_space[i];}cout << " 調用拷貝構造函數 " << endl;
}// 析構函數
template <typename T>
Array<T>::~Array()
{if (m_space != NULL){// 釋放 new T[m_length] 分配的內存 delete[] m_space;m_space = NULL;m_length = 0;}cout << " 調用析構函數 " << endl;
}// 數組下標 [] 操作符重載
template <typename T>
T& Array<T>::operator[](int i)
{return m_space[i];
}// 等號 = 操作符重載
template <typename T>
Array<T>& Array<T>::operator=(const Array<T>& a)
{if (this->m_space != NULL){// 釋放 new int[m_length] 分配的內存 delete[] this->m_space;this->m_space = NULL;}// 設置數組長度this->m_length = a.m_length;// 創建數組this->m_space = new T[m_length];// 為數組賦值for (int i = 0; i < m_length; i++){this->m_space[i] = a.m_space[i];}cout << " 調用 等號 = 操作符重載 函數" << endl;// 返回是引用類型// 返回引用就是返回本身// 將 this 指針解引用, 即可獲取數組本身return *this;
}
3、Test.cpp 主函數代碼文件
#define _CRT_SECURE_NO_WARNINGS
#include "iostream"
using namespace std; // 此處注意, 類模板 聲明與實現 分開編寫
// 由于有 二次編譯 導致 導入 .h 頭文件 類模板函數聲明 無法找到 函數實現
// 必須 導入 cpp 文件
#include "Array.cpp"class Student
{friend ostream& operator<<(ostream& out, const Student& s);
public:Student(){m_age = 10;// 創建一個數組個數為 1 的數組, 存放 '\0' 值// 這是一個空字符串m_name = new char[1];strcpy(m_name, "");}Student(const char* name, int age) {// 計算字符串大小// 總的大小是 字符個數 + \0 字符, 因此多一個字節int len = strlen(name) + 1;// 根據字符串大小創建 字符數組m_name = new char[len];strcpy(this->m_name, name);this->m_age = age;}Student(const Student& s) {// 計算字符串大小// 總的大小是 字符個數 + \0 字符, 因此多一個字節int len = strlen(s.m_name) + 1;// 根據字符串大小創建 字符數組m_name = new char[len];strcpy(this->m_name, s.m_name);this->m_age = s.m_age;}void printT() {cout << "name : " << m_name << " , age : " << m_age << endl;}~Student(){if (m_name != NULL){delete[] m_name;m_name = NULL;}}// 重載等號操作符Student& operator=(const Student& obj) {if (m_name != NULL) {delete[] m_name;m_name = NULL;}// 計算字符個數int len = strlen(obj.m_name) + 1;// 根據字符串大小創建 字符數組m_name = new char[len];strcpy(this->m_name, obj.m_name);this->m_age = obj.m_age;return *this;}private:char* m_name;int m_age;
};// 重載左移運算符實現
ostream& operator<<(ostream& out, const Student& s) {out << "name : " << s.m_name << " , age : " << s.m_age << " ; ";return out;
}int main() {// 驗證 有參構造函數Array<Student> array(3);Student s0("Tom", 18), s1("Jerry", 12), s2("Jack", 16);array[0] = s0;array[1] = s1;array[2] = s2;// 遍歷數組 打印數組元素for (int i = 0; i < 3; i++) {array[i].printT();}cout << array << endl;// 控制臺暫停 , 按任意鍵繼續向后執行system("pause");return 0;
}
4、Test.cpp 主函數代碼文件
執行結果 :
調用有參構造函數
name : Tom , age : 18
name : Jerry , age : 12
name : Jack , age : 16
name : Tom , age : 18 ; name : Jerry , age : 12 ; name : Jack , age : 16 ;
Press any key to continue . . .