C++11語言(三)

一、引言

? ? ? ? 上期我們介紹了C++11的大部分特性。C++11的初始化列表、auto關鍵字、右值引用、萬能引用、STL容器的的emplace函數。

????????要補充的是右值引用是不能取地址的,我們程序員一定要遵守相關的語法。操作是未定義的很危險。

二、????????仿函數和函數指針

? ? ? ? 我們先從仿函數的形成和函數指針的形成開始介紹起來,有了這個大家會更好的清楚lamda表達式、裝配器function和綁定器bind。

? ? ? ? 仿函數顧名思義就是類似于函數,肯定不是函數,但是肯定具有和函數一樣的功能。那問題來了為什么不用函數指針呢?

? ? ? ? 函數指針使用起來還是有點問題的。首先需要typedef一個固定的函數類型。沒錯這個函數是固定的不可變的,參數類型是固定的。那為什么我們不用上一章講過的C語言不定參數。C語言的不定參數也需要傳入類型,這個點是比較麻煩的。而且明確的就是類型不是字符串,因為不定參數是宏定義而不是真正的函數。

? ? ? ? 為了方便比較我們也來使用一下函數指針吧。

#include <stdio.h>// 函數指針的模擬,隨便寫的類型名。
// 打印數組。// 定義函數指針
typedef void (*ptest)(int* a, int n);void test(int* a, int n)
{for (int i = 0;i < n;++i){printf("%d   ", a[i]);}printf("\n");
}void function(ptest func,int* a,int n)
{func(a,n);
}int main()
{int a[] = { 1,2.3,4,5,6,7,8 };int n = sizeof(a) / sizeof(a[0]);function(test,a,n);return 0;
}

? ? ? ? 那我們是如何實現仿函數的呢?C++用的最多的就是類和對象,利用模板的特性我們可以傳入各種不同的類,那仿函數的原型毫無疑問就是類,類中包含的函數傳入到另一個函數或是其他類中也可以調用內部中的函數。這樣我們實現一個基本的多態。多種形態。和特殊化處理。那我們該如何命名類中的函數。既然叫函數就應該和函數差不多,不然可讀性不是很好用的也麻煩,而且本來就是當函數來使用沒必要取什么特殊的名字。這樣我們就實現出了一個類函數。

class 類名
{public:// 運算符重載 : operator + 符號 // 就可以通過符號與類結合調用。// 這完全就是C++基于類和變量之間不同的考量。返回類型 operator () (參數){; // …………所要調用的方法和所要實現的內容。}
};     //這個分號千萬不要忘記了,就把它當做是C語言定義變量。

? ? ? ? 那下面我們來做一個簡單的練習。首先我們要知道C++中包含排序方法。雖然排序的方法多種多樣,但是排序標準都各有不同。并不一定是基于簡單的比較大小,有可能是運用了特殊的比較方法。還可能會有順序的差異例如升序、降序。所以我們使用C++庫<algorithm>中std::sort()函數進行排序。另外排序標準由我們來進行確定。

#include <iostream>
#include <algorithm>// 仿函數。
class Func
{
public:// 這里依據函數實現的不同而返回類型不同。// 還可以加入模板。template<typename T>bool operator () (T i, T j){// 升序的話是后面的數據大于前面的數據。// 我們為了演示反其道而行之。return i > j;}
};int main()
{int a[] = { 1 , 2 , 4 , 5 , 6 , 7 , 8 };int n = sizeof(a) / sizeof(a[0]);// 起始位置和末尾位置的下一個(有效位置的下一個,也就是無效位置。更確切的講是規定范圍。)// 最后一個參數是用來傳遞排序標準的,什么都不傳的話默認是升序(缺省參數)。// 如果是STL容器的話直接用里面的begin函數和end函數。std::sort(a, a + n);// 范圍forfor (int x : a){std::cout << x << "  ";}std::cout << std::endl;std::sort(a, a + n, Func());for (int x : a){std::cout << x << "  ";}std::cout << std::endl;return 0;
}

三、????????Lamda表達式

? ? ? ? 上述的仿函數雖然與函數指針簡便不少,例如不用考慮參數的類型,不用定義函數指針。但C++標準委員會還是覺得不好用,能不能出現一個匿名的函數呢?直接不用寫名字。這個其實最開始是python最先搞出來的。C++看到后覺得好用直接也實現一個出來了。底層就是我們上面實現的仿函數,只是用完就丟這個特性和仿函數不一樣。

[捕捉列表:值捕捉&+變量、對象=引用。值引用:變量、對象=const引用]
// 如果只有一個&,說明是引用函數中的所有變量、對象。
->返回類型(沒有就省略這個->)(參數類型)
{;     //…………實現的方法。
}

? ? ? ? 接下來我們還是使用std::sort()函數進行練習。

????????只需要更改其中的一行代碼就行了。lamda表達式其實就是匿名函數(沒有名字,說明接下來無法通過名字來調用,同時也意味著無法遞歸。(函數自己本身調用一個新的原本函數自己本身,可以理解創建新的自己分身。)

std::sort(a, a + n,[](int i,int j)
{return i > j;
});

四、????????包裝器function、綁定器bind介紹

? ? ? ?這兩個函數都是庫<functional>文件中的類。

????????std::function和函數指針有著異曲同工之妙,在項目中對于函數的發封裝起到非常大的作用。std::function可以與lamda表達式、仿函數和bind裝配器有著不錯的兼容。函數指針并不能做到這點。此外函數指針為了重復使用一般都是泛型編程(返回值或是參數都是用void*,這樣就可以不用管參數的類型,參數的數量,返回值的數量和類型,但是這樣出錯了非常不好檢查出來。)

? ? ? ? std::bind包裝器,常常用于為了一個類能夠調用其他類中的類函數,或者是固定好函數的參數,實現編程的隱蔽性和泛型編程。

? ? ? ? 下面我們以打印數組來做實例對象。

#include <iostream>
#include <algorithm>
#include <functional>class Func
{
public:void print(int* a,int n){for (int i = 0; i < n; ++i){std::cout << a[i] << "  ";}std::cout << std::endl;}
};int main()
{int a[] = { 1 , 2 , 4 , 5 , 6 , 7 , 8 };int n = sizeof(a) / sizeof(a[0]);// 我們嘗試使用std::function包裝仿函數。// 還可以和模板進行搭配。// 調用未加static的類函數需要用到類中的指針或是引用。std::function<void(Func, int*, int)> func1 = &Func::print;func1(Func(), a, n);// 綁定器可以固定參數,調用更加方便,也防止別人亂改,也通過std::placeholders庫中的_n來確定該輸入幾個參數。// 一般可以將std::bind看作function的初始化類型。// 使用std::bind賦值給std::function的時候,記得已經在bind固定了的參數的類型從function中去掉。// 因為參數已經固定無需再傳參了。std::function<void(int*,int)> func2 = std::bind(&Func::print,Func(), std::placeholders::_1,std::placeholders::_2);func2(a, n);std::function<void()> func3 = std::bind(&Func::print, Func(), a, n);// 當然可以直接將所有參數都固定,直接變為無參函數。func3();return 0;
}

五、????????智能指針

????????我們在系統申請空間,總是要還的,所以我們常常需要手動釋放它。但是這非常不方便。所以C++搞出了智能指針,自動釋放申請空間或是自動關閉某個開關。但是最初的智能指針被罵的非常慘。因為C++根本沒有考慮多引用、多指向的情況。unique_ptr是明確了只有一個指針指向這塊空間。

? ? ? ? shared_ptr是允許多個指針指向申請的空間,運用了引用計數的概念,初始化時申請了一塊空間進行統計使用同一空間的指針數量。當引用為零時自動釋放申請空間。都使用shared_ptr了,肯定賦值的對象、接受的參數肯定也是shared_ptr。

? ? ? ? weak_ptr虛指針,防止shared_ptr指向過多,不能釋放,造成內存泄漏,從而導致服務器崩潰。在shared_ptr互相指向時使用,shared_ptr不增加引用計數。相互指向造成你不釋放,我也不釋放的難題。不能單獨使用,只能和shared_ptr一起使用。

template<class T>class unique_ptr{public:explicit unique_ptr(T* ptr):_ptr(ptr){}~unique_ptr(){if (_ptr){cout << "delete:" << _ptr << endl;delete _ptr;}}// 像指針?樣使? T& operator*(){return *_ptr;}T* operator->(){return _ptr;}unique_ptr(const unique_ptr<T>& sp) = delete;unique_ptr<T>& operator=(const unique_ptr<T>& sp) = delete;unique_ptr(unique_ptr<T>&& sp):_ptr(sp._ptr){sp._ptr = nullptr;}unique_ptr<T>& operator=(unique_ptr<T>&& sp){delete _ptr;_ptr = sp._ptr;sp._ptr = nullptr;}private:T* _ptr;};template<class T>class shared_ptr{public:explicit shared_ptr(T* ptr = nullptr): _ptr(ptr), _pcount(new int(1)){}template<class D>
{return _ptr;}int use_count() const{return *_pcount;}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}private:T* _ptr;int* _pcount;//atomic<int>* _pcount; function<void(T*)> _del = [](T* ptr) {delete ptr; };};// 需要注意的是我們這?實現的shared_ptr和weak_ptr都是以最簡潔的?式實現的, // 只能滿?基本的功能,這?的weak_ptr lock等功能是?法實現的,想要實現就要 // 把shared_ptr和weak_ptr?起改了,把引?計數拿出來放到?個單獨類型,shared_ptr // 和weak_ptr都要存儲指向這個類的對象才能實現,有興趣可以去翻翻源代碼 template<class T>class weak_ptr{public:weak_ptr(){}weak_ptr(const shared_ptr<T>& sp):_ptr(sp.get()){}weak_ptr<T>& operator=(const shared_ptr<T>& sp){_ptr = sp.get();return *this;}
private:T* _ptr = nullptr;};
}

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

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

相關文章

性能優化三劍客:`memo`, `useCallback`, `useMemo` 詳解

性能優化三劍客&#xff1a;memo, useCallback, useMemo 詳解 作者&#xff1a;碼力無邊各位React性能調優師&#xff0c;歡迎來到《React奇妙之旅》的第十二站&#xff01;我是你們的伙伴碼力無邊。在之前的旅程中&#xff0c;我們已經掌握了如何構建功能豐富的組件&#xff0…

好用的電腦軟件、工具推薦和記錄

固態硬盤讀寫測試 AS SSD Benchmark https://gitee.com/qlexcel/common-resource-backup/blob/master/AS%20SSD%20Benchmark.exe 可以測試SSD的持續讀寫、4K隨機讀寫等性能。也可以測試HDD的性能。 操作非常簡單&#xff0c;點擊Start(開始)即可測試。 體積小&#xff0c;免安…

Spring Task快速上手

一. 介紹Spring Task 是Spring框架提供的任務調度工具&#xff0c;可以按照約定的時間自動執行某個代碼邏輯&#xff0c;無需依賴額外組件&#xff08;如 Quartz&#xff09;&#xff0c;配置簡單、使用便捷&#xff0c;適合處理周期性執行的任務&#xff08;如定時備份數據、定…

函數(2)

6.定義函數的終極絕殺思路&#xff1a;三個問題&#xff1a;1.我定義函數&#xff0c;是為了干什么事情 函數體、2.我干完這件事&#xff0c;需要什么才能完成 形參3.我干完了&#xff0c;調用處是否需要繼續使用 返回值類型需要繼續使用 必須寫不需要返回 void小程序#include …

BGP路由協議(一):基本概念

###BGP概述 BGP的版本&#xff1a; BGP-1 RFC1105BGP-2 RFC1163BGP-3 RFC1267BGP-4 RFC1771 1994年BGP-4 RFC4271 2006年 AS Autonomous System 自治系統&#xff1a;由一個單一的機構或者組織所管理的一系列IP網絡及其設備所構成的集合 根據工作范圍的不同&#xff0c;動態路…

mit6.031 2023spring 軟件構造 筆記 Testing

當你編碼時&#xff0c;目標是使程序正常工作。 但作為測試設計者&#xff0c;你希望讓它失敗。 這是一個微妙但重要的區別。 為什么軟件測試很難&#xff1f; 做不到十分詳盡&#xff1a;測試一個 32 位浮點乘法運算 。有 2^64 個測試用例&#xff01;隨機或統計測試效果差&am…

【Unity開發】Unity核心學習(三)

四、三維模型導入相關設置 1、Model模型頁簽&#xff08;1&#xff09;場景相關&#xff08;2&#xff09;網格相關&#xff08;3&#xff09;幾何體相關2、Rig操縱&#xff08;骨骼&#xff09;頁簽 &#xff08;1&#xff09;面板基礎信息&#xff08;i&#xff09;None&…

C#語言入門詳解(17)字段、屬性、索引器、常量

C#語言入門詳解&#xff08;17&#xff09;字段、屬性、索引器、常量前言一、字段 Field二、屬性三、索引器四、常量內容來自劉鐵猛C#語言入門詳解課程。 參考文檔&#xff1a;CSharp language specification 5.0 中文版 前言 類的成員是靜態成員 (static member) 或者實例成…

Total PDF Converter多功能 PDF 批量轉換工具,無水印 + 高效處理指南

在辦公場景中&#xff0c;PDF 格式的 “不可編輯性” 常成為效率瓶頸 —— 從提取文字到格式轉換&#xff0c;從批量處理到文檔加密&#xff0c;往往需要多款工具協同。Total PDF Converter 破解專業版作為一站式 PDF 解決方案&#xff0c;不僅支持 11 種主流格式轉換&#xff…

[Windows] WPS官宣 64位正式版(12.1.0.22525)全新發布!

[Windows] WPS官宣 64位正式版 鏈接&#xff1a;https://pan.xunlei.com/s/VOYepABmXVfXukzlPdp8SKruA1?pwdeqku# 自2024年5月&#xff0c;WPS 64位版本在WPS社區發布第一個內測體驗安裝包以來&#xff0c;在近一年多的時間里&#xff0c;經過超過3萬名WPS體驗者參與版本測試…

WinExec

函數原型&#xff1a; __drv_preferredFunction("CreateProcess","Deprecated. See MSDN for details") WINBASEAPI UINT WINAPI WinExec(__in LPCSTR lpCmdLine,__in UINT uCmdShow); preferred : 更好的 __drv_preferredFunction("CreateProcess…

基于GA遺傳優化的雙向LSTM融合多頭注意力(BiLSTM-MATT)時間序列預測算法matlab仿真

目錄 1.前言 2.算法運行效果圖預覽 3.算法運行軟件版本 4.部分核心程序 5.算法仿真參數 6.算法理論概述 7.參考文獻 8.算法完整程序工程 1.前言 時間序列預測是機器學習領域的重要任務&#xff0c;廣泛應用于氣象預報、金融走勢分析、工業設備故障預警等場景。傳統時間…

Multi-Head RAG: Solving Multi-Aspect Problems with LLMs

以下是對論文《Multi-Head RAG: Solving Multi-Aspect Problems with LLMs》的全面解析&#xff0c;從核心問題、方法創新到實驗驗證進行系統性闡述&#xff1a;??一、問題背景&#xff1a;傳統RAG的局限性??傳統檢索增強生成&#xff08;RAG&#xff09;在處理??多維度復…

Jenkins 全方位指南:安裝、配置、部署與實戰應用(含圖解)

一、Jenkins 安裝 1.1 系統要求 基礎環境&#xff1a;Java 8 或 Java 11&#xff08;推薦&#xff09;、至少 2GB 內存、10GB 以上磁盤空間 支持系統&#xff1a;Windows、Linux&#xff08;Ubuntu/CentOS&#xff09;、macOS 網絡端口&#xff1a;默認使用 8080 端口&…

以國產IoTDB為代表的主流時序數據庫架構與性能深度選型評測

> &#x1f4a1; 原創經驗總結&#xff0c;禁止AI洗稿&#xff01;轉載需授權 > 聲明&#xff1a;本文所有觀點均基于多個領域的真實項目落地經驗總結&#xff0c;數據說話&#xff0c;拒絕空談&#xff01; 目錄 引言&#xff1a;時序數據庫選型的“下半場” 一、維…

7.2elementplus的表單布局與模式

基礎表單<template><el-form ref"ruleFormRef" :model"form" :rules"rules" label-width"100px"><el-form-item label"用戶名" prop"username"><el-input v-model"form.username"…

PyTorch實戰(3)——PyTorch vs. TensorFlow詳解

PyTorch實戰&#xff08;3&#xff09;——PyTorch vs. TensorFlow詳解0. 前言1. 張量2. PyTorch 模塊2.1 torch.nn2.2 torch.optim2.3 torch.utils.data3. 使用 PyTorch 訓練神經網絡小結系列鏈接0. 前言 PyTorch 是一個基于 Torch 庫的 Python 機器學習庫&#xff0c;廣泛用…

在win服務器部署vue+springboot + Maven前端后端流程詳解,含ip端口講解

代碼打包與基本配置 首先配置一臺win系統服務器&#xff0c;開放你前端和后端運行的端口&#xff0c;如80和8080 前端打包 前端使用vue3&#xff0c;在打包前修改項目配置文件&#xff0c;我使用的是vite所以是vite.config.js。 import { defineConfig } from vite import …

Springcloud-----Nacos

一、Nacos的安裝 Nacos是阿里推出的一種注冊中心組件&#xff0c;并且已經開源&#xff0c;目前是國內最為流行的注冊中心組件。下面我們來了解一下如何安裝并啟動Nacos。 Nacos是一個獨立的項目&#xff0c;我們可以去GitHub上下載其壓縮包來使用&#xff0c;地址如下&#x…

騰訊云重保流程詳解:從預案到復盤的全周期安全防護

摘要 騰訊云針對國家級重大活動&#xff08;如進博會、冬奧會等&#xff09;提供的網絡安全保障服務&#xff08;重保&#xff09;是一套系統化的主動防御體系。本文從“事前準備”“事中響應”“事后復盤”三個核心階段出發&#xff0c;結合民生銀行等典型用戶的實戰案例&…