【C++】泛型編程 ? ( 類模板示例 - 數組類模板 | 容器思想 | 自定義類可拷貝 - 深拷貝與淺拷貝 | 自定義類可打印 - 左移運算符重載 )

文章目錄

  • 一、容器思想
    • 1、自定義類可拷貝 - 深拷貝與淺拷貝
    • 2、自定義類可拷貝 - 代碼示例
    • 3、自定義類可打印 - 左移運算符重載
  • 二、代碼示例
    • 1、Array.h 頭文件
    • 2、Array.cpp 代碼文件
    • 3、Test.cpp 主函數代碼文件
    • 4、執行結果






一、容器思想




1、自定義類可拷貝 - 深拷貝與淺拷貝


上一篇博客 【C++】泛型編程 ? ( 類模板示例 - 數組類模板 | 構造函數和析構函數 的 聲明與實現 | 普通成員函數 的 聲明與實現 | 外部友元函數 的 聲明與實現 ) 中 , 實現了一個 數組 類模板 , 數組 中的 數據元素 是 泛型類型 , 可以是任意類型 ;

也就是說 , 該數組可以存儲 任意類型 的數據 , 包括 自定義類對象 ;

該數組 就是一個 數據的容器 ;

數組中 每個元素 插入數據時 , 其本質是一個 拷貝操作 , 數組 的 內存空間 在 聲明實際類型 以及 創建 時 , 就已經確定了 , 向數組中插入元素 , 就是將 已有的 數據 拷貝到 已經分配好的內存中 ;

向 數據容器 ( 數組 ) 中插入的數據 , 必須可以被 拷貝 , 如果 不能被拷貝 , 就會出現插入數據失敗的問題 ;


容器 中的 類型 可拷貝 , 就是要求 容器中的 數據類型 都是 值語義 , 不是 引用語義 ,

向 容器 中插入元素 , 就是拷貝 數據內容 到容器中 , 要將真實的值拷貝進去 , 不是將 引用地址 拷貝進去 ,

就是 深拷貝 和 淺拷貝 的問題 ;


下面的示例中 , 自定義類中的成員變量 char m_name[32] 是 在定義時 , 直接分配好的 ,

如果 自定義類 中有 指針類型的成員變量 , 如 char* m_name , 涉及到 動態分配內存 , 如果沒有定義 拷貝構造函數 , 默認的 拷貝構造函數 是 淺拷貝 函數 , 直接將 指針地址 簡單拷貝 , 這就是 不可被拷貝的情況 ;

那么多個 數組元素 就會共享 相同的 堆內存 數據 , 此時就會出現問題 ;


如果遇到了上述問題 , 定義了 char* m_name 成員變量 , 涉及到 動態分配內存 , 那么 該自定義類 必須自己實現 深拷貝 的 拷貝構造函數 ;


編寫的類 , 可以存儲到 數組類模板 容器 中 , 那么 該類 必須 支持 拷貝工作 , 具體一些就是 深拷貝 工作 ;


2、自定義類可拷貝 - 代碼示例


下面簡單實現一個類 , 該類中維護了 2 個成員變量 , char m_name[32] 數組變量 和 int m_age 變量 , 這兩個 成員 都是在 創建時 就會分配內存空間 , 不存在 深拷貝問題 ;

如果 char m_name[32] 數組變量 改為 char* m_name 指針變量 , 就需要考慮 深拷貝問題了 ;

class Student
{
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;
};

3、自定義類可打印 - 左移運算符重載


數組類模板 中 , 實現了 左移運算符 打印日志 , 如果 數組中 存儲 自定義類對象 想要通過 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;
}




二、代碼示例




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;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;
}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、執行結果


執行結果 :

 調用有參構造函數
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 . . .

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/165342.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/165342.shtml
英文地址,請注明出處:http://en.pswp.cn/news/165342.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

百戰python02-語言元素

文章目錄 指令與程序變量與類型變量命名變量的使用運算符賦值運算符比較運算符和邏輯運算符練習1:華氏溫度轉換為攝氏溫度練習2:輸入圓的半徑計算計算周長和面積練習3:輸入年份判斷是不是閏年字符串常用操作注:需要對python有基本了解,可查看本作者python基礎專欄,有任何問…

大模型生態新篇章:以AI Agent為引,助企業創新應用落地

文 | 智能相對論 作者 | 沈浪 以聊天機器人、虛擬助手、智能客服等為代表的對話式人工智能 (Conversational AI Agents ) 在具體服務場景中的應用已經十分普遍。今年以來&#xff0c;隨著大模型技術的爆發與加持&#xff0c;對話式AI被市場賦予了更高的期望。 “所有行業都值…

Spring 事務失效的7種場景, 事務失效后如何進行處理

文章目錄 簡單說說spring事務失效的場景Spring 事務失效的7種場景1.1、未啟用[spring事務管理](https://so.csdn.net/so/search?qspring事務管理&spm1001.2101.3001.7020)功能1.2、方法不是public類型的1.3、數據源未配置事務管理器1.4、自身調用問題1.5、異常類型錯誤1.6…

《golang設計模式》第三部分·行為型模式-07-觀察者模式(Observer)/發布者—訂閱者模式

文章目錄 1. 概念1.1 角色1.2 類圖 2. 代碼示例2.1 代碼2.2 類圖 1. 概念 觀察者&#xff08;Observer&#xff09;指當目標對象狀態發生變化后&#xff0c;對狀態變化事件進行響應或處理的對象。 1.1 角色 Subject&#xff08;抽象主題&#xff09;&#xff1a; 它可以有多…

微服務實戰系列之Feign

前言 不知不覺&#xff0c;“微服務實戰系列”已完成了六篇&#xff0c;每篇都聚焦一個主題&#xff0c;目的是便于各位盆友能夠快速、全面地接收和消化。 博主從服務注冊到服務監控&#xff0c;從服務路由到服務安全&#xff0c;從身份認證到加密技術均有涉獵。凡此均有關微服…

Java核心知識點整理大全10-筆記

往期快速傳送門&#xff1a; Java核心知識點整理大全-筆記_希斯奎的博客-CSDN博客文章瀏覽閱讀9w次&#xff0c;點贊7次&#xff0c;收藏7次。Java核心知識點整理大全https://blog.csdn.net/lzy302810/article/details/132202699?spm1001.2014.3001.5501 Java核心知識點整理…

【LeetCode刷題】--67.二進制求和

67.二進制求和 方法&#xff1a;模擬計算 class Solution {public String addBinary(String a, String b) {StringBuilder ans new StringBuilder();int carry 0;for(int ia.length()-1,jb.length()-1;i>0||j>0;i--,j--){int sum carry;sum i >0 ? a.charAt(i) …

web:[WUSTCTF2020]樸實無華

題目 點開頁面顯示如下 頁面顯示了一行報錯&#xff1a;Cannot modify header information - headers already sent by (output started at /var/www/html/index.php:3) in /var/www/html/index.php on line 4 意思為不能修改報頭信息-報頭已經發送(輸出開始于/var/www/html/i…

vue3 websocket連接 發送數據

先建一個websocket.js放在項目中&#xff0c;內容如下&#xff1a; var websock null; let rec; //斷線重連后&#xff0c;延遲5秒重新創建WebSocket連接 rec用來存儲延遲請求的代碼 let isConnect false; //連接標識 避免重復連接 let checkMsg "heartbeat"; /…

MySQL與Redis如何保證數據的一致性

文章目錄 MySQL與Redis如何保證數據的一致性&#xff1f;不好的方案1. 先寫 MySQL&#xff0c;再寫 Redis2. 先寫 Redis&#xff0c;再寫 MySQL3. 先刪除 Redis&#xff0c;再寫 MySQL 好的方案4. 先刪除 Redis&#xff0c;再寫 MySQL&#xff0c;再刪除 Redis5. 先寫 MySQL&am…

C# 數據庫封裝

最近有些地方用到c#&#xff0c;研究了一下&#xff0c;也有數據庫方面的操作&#xff0c;那就繼續封裝&#xff0c;自己用起來好用一點。 數據庫連接 using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Text; using Sys…

Leetcode算法系列| 1. 兩數之和(四種解法)

目錄 1.題目2.題解解法一&#xff1a;暴力枚舉解法二&#xff1a;哈希表解法解法三&#xff1a;雙指針(有序狀態)解法四&#xff1a;二分查找(有序狀態) 1.題目 給定一個整數數組 nums 和一個整數目標值 target&#xff0c;請你在該數組中找出 和為目標值 target 的那 兩個 整數…

『RabbitMQ』入門指南(安裝,配置,應用)

前言 RabbitMQ 是在 AMQP&#xff08;Advanced Message Queuing Protocol&#xff09; 協議標準基礎上完整的&#xff0c;可復用的企業消息系統。它遵循 Mozilla Public License 開源協議&#xff0c;采用 Erlang 實現的工業級的消息隊列(MQ)服務器&#xff0c;建立在 Erlang …

產品經理提問常用的ChatGPT通用提示詞模板

如何評估產品市場的潛力和可行性&#xff1f; 如何定義和明確產品的目標用戶和需求&#xff1f; 如何進行競品分析和比較&#xff0c;制定產品的差異化策略&#xff1f; 如何設計產品的功能和特性&#xff0c;滿足用戶需求&#xff1f; 如何制定產品的定價策略和銷售計劃&a…

qml View3D使用介紹

在Qt Quick 3D中,View3D 是一個用于展示 3D 內容的 QML 類型。View3D 允許你將 3D 場景集成到 Qt Quick 2D 用戶界面中,這意味著你可以在傳統的 2D UI 元素(如按鈕、文本和圖像)與 3D 圖形之間無縫地進行整合。 View3D 提供了一個視口,用于渲染 3D 場景。它可以包括多個 …

HTTPS攻擊怎么防御?

HTTPS 簡介 超文本傳輸安全協議&#xff08; HTTPS &#xff09;是一種通過計算機網絡進行安全通信的傳輸協議。HTTPS 經由 HTTP 進行通信&#xff0c;但利用 SSL/TLS 來加密數據包。 HTTPS 開發的主要目的&#xff0c;是提供對網站服務器的身份認證&#xff0c;保護交換數據的…

批量將本地N個英文Html文檔進行中文翻譯-操作篇

Unity3D特效百例案例項目實戰源碼Android-Unity實戰問題匯總游戲腳本-輔助自動化Android控件全解手冊再戰Android系列Scratch編程案例軟考全系列Unity3D學習專欄藍橋系列ChatGPT和AIGC &#x1f449;關于作者 專注于Android/Unity和各種游戲開發技巧&#xff0c;以及各種資源分…

QtCreator9.02不支持JDK11解決

最終效果 使用Android Studio 下載Android SDK Platform 31與Sources for Android 31 下載Android SDK Build Tools 31.0.0 下載NDK 25.1 ,23.1 ,21.3 重要: 下載Android SDK Command-Line Tools ,選擇10.0或者9.0其中一個版本 其它版本不支持JDK11 ,本例選擇10.0 下載CMak…

如何進行MySQL的主從復制(MySQL5.7)

背景&#xff1a;在一些Web服務器開發中&#xff0c;系統用戶在進行數據訪問時&#xff0c;基本都是直接操作數據庫MySQL進行訪問&#xff0c;而這種情況下&#xff0c;若只有一臺MySQL服務器&#xff0c;可能會存在如下問題 數據的讀和寫的所有壓力都會由一臺數據庫獨…

淺析jdk8所包含的主要特性

至今Java 8仍然是許多開發者首選的JDK版本&#xff0c;Java 8的生態系統非常成熟&#xff0c;許多庫和框架都已經適配了Java 8。遷移到新的Java版本可能需要重新評估和調整現有的依賴關系&#xff0c;這對于一些大型項目可能是一個挑戰。那么Java 8有哪些特性讓多數開發者鐘愛呢…