C++基础课—郑莉9-
第九章 群體類和群體數組的組
9.1 函數模版與類模版
?函數模版與類模版的設計是為了代碼重用,它通過參數多態化實現,就是將程序所處理的對象的類型參數化,使得一段程序可以用于處理多種不同類型的對象。
? ? ? ? 函數模版的一個具體的例子如下:
#include<iostream> using namespace std;template <typename T> T abs(T x) {return x>0? x:-x; } int main() {int n = 5;double d = -5.5;cout<<"abs(n): "<<abs(n)<<endl;cout<<"abs(m): "<<abs(d)<<endl;return 0; }? ? ? ?
????????需要注意:
? ? ? ? ? ? ? ? 1. 函數模版在編譯時不會產生目標代碼,只有在實例化后才產生目標代碼。
? ? ? ? ? ? ? ? 2. 被多個源文件引用的函數模版,應當將其函數體一同放入頭文件中。
? ? ? ? ? ? ? ? 3. 函數指針只能指向函數模版的實例。
? ? ? ? ?類模版:
? ? ? ? ? ? ? ? 使用類模版可以使用戶為類定義一種模式,使類中的某數據成員、類中成員函數的參數、返回值、局部變量能取任意類型,包括系統類型和自己定義的類型。
? ? ? ? ? ? ? ? 類是對事物的抽象,類模版是對不同類公共性質的抽象,是更高層次的抽象。類模版聲明的語法如下:
????????????????????????
????????????????如果需要在類模板以外定義其成員函數,則要采用以下的形式:
????????????????????????
????????????????使用一個模板類來建立對象時,應按如下形式聲明: ????????????????????????9.2 線性群體
? ? ? ? 線性群體的概念
? ? ? ? ? ? ? ? 1. 直接訪問(數組類)
? ? ? ? ? ? ? ? 2. 順序訪問
? ? ? ? ? ? ? ? 3.索引訪問
? ? ? ? ? ? ? ? 數組類:靜態數組在編譯時已經確定其大小,后續無法修改,并且靜態數組不能避免下標越界。為解決這個問題,我們設計一種動態數組Array,它由任意多個位置連續的、類型相同的元素組成,其元素個數可在程序運行時改變,功能與vector相近。
? ? ? ? ? ? ? ? 下面代碼我們簡單實現vector。
? ? ? ? ? ? ? ? Myvector.hpp:
// // Myvector.hpp // personalaccount // // Created by 劉博文 on 2022/7/18. //#ifndef Myvector_hpp #define Myvector_hpp#include <stdio.h> #include<iostream> #include<cstring> #include<cassert> template<typename T> class MyVector { public:MyVector(int size = 10);~MyVector();//訪問T& at(int index) const;T& front() const;T& back() const;T& operator[](int index);//容量bool empty() const;int size() const;int capacity() const;//修改void clear();void insert(int index, const T& d);void remove(int index);void push_back(const T& d);void pop_back();private:T* data;int length;int current_pos;}; template<typename T> MyVector<T>::MyVector(int size) :length(size), current_pos(0) {if (data != nullptr){delete[] data;data = nullptr;}data = new T[length];memset(data, 0, length * sizeof(T)); } template<typename T> MyVector<T>::~MyVector() {if (data != nullptr){delete[] data;data = nullptr;} }template<typename T> T& MyVector<T>::at(int index) const {assert(index > 0 || index < current_pos);return data[index]; }template<typename T> T& MyVector<T>::front() const {assert(current_pos > 0);return data[0]; }template<typename T> T& MyVector<T>::back() const {assert(current_pos > 0);return data[current_pos - 1]; }template<typename T> T& MyVector<T>::operator[](int index) {assert(index > 0 || index < current_pos);return data[index]; }template<typename T> bool MyVector<T>::empty() const {return current_pos == 0 ? true : false; }template<typename T> int MyVector<T>::size() const {return current_pos; }template<typename T> int MyVector<T>::capacity() const {return length; }template<typename T> void MyVector<T>::clear() {current_pos = 0; }template<typename T> void MyVector<T>::insert(int index, const T& d) {assert(index > 0 || index < current_pos);if (current_pos == length){T* temp = new T[length + 10];memset(temp, 0, (length + 10) * sizeof(T));memcpy(temp, data, length * sizeof(T));length += 10;delete[]data;data = nullptr;data = temp;}memcpy(data + index + 1, data + index, (length - index) * sizeof(T));data[index] = d;// 當前數組指針 +1current_pos++; } template<typename T> void MyVector<T>::remove(int index) {assert(index > 0 || index < current_pos);memcpy(data + index, data + index + 1, (current_pos - index) * sizeof(T));current_pos--; }template<typename T> void MyVector<T>::push_back(const T& d) {// 檢查當前數組大小是否可用if (current_pos == length) {// 擴容,每次擴容 10 個數據大小的空間T* temp = new T[length + 10];memset(temp, 0, (length + 10) * sizeof(T));memcpy(temp, data, length * sizeof(T));length += 10;delete[] data;data = nullptr;data = temp;}// 插入數據data[current_pos] = d;// 當前數組指針 +1current_pos++;} template<typename T> void MyVector<T>::pop_back() {assert(current_pos > 0);current_pos--; }#endif /* Myvector_hpp */? ? ? ? Myvector.cpp
// // Myvector.cpp // personalaccount // // Created by 劉博文 on 2022/7/18. //#include "Myvector.hpp" #include<iostream>using namespace std;int main() {MyVector<int> vec;for (int i = 0; i < vec.capacity(); i++)vec.push_back(i);vec.push_back(10);cout << "capacity: " << vec.capacity() << endl;for (int i = 0; i < vec.size(); i++)cout << vec.at(i) << ", ";cout << endl;vec.insert(0, 5);vec.insert(1, 15);for (int i = 0; i < vec.size(); i++)cout << vec[i] << ", ";cout << endl;vec.remove(1);vec.pop_back();for (int i = 0; i < vec.size(); i++)cout << vec[i] << ", ";cout << endl;cout << "front: " << vec.front() << ", back: " << vec.back() << endl;return 0; }????????
? ? ? ? ? ? ? ? 上面的代碼是之前學習C++時自己的練習,功能為簡單實現vector。對比書中的例子,缺少運算符重載、copy構造函數等,一般copy構造函數和運算符重載會同時出現。
? ? ? ? 鏈表類:
? ? ? ? ? ? ? ? 概念就是數據結構中的鏈表。存儲不連續,需要指針對其數據進行指向。自己定義鏈表類容易內存泄露導致內存不足程序崩潰,再STL中有定義好的鏈表類,完全滿足我們的需求。
????????????????書中有鏈表類的實現。需要預先定義一個鏈表結構node,再定義鏈表數據結構,數據結構的private中需要表頭表尾,前驅和當前節點等指針。公有的public包含對鏈表的操作。
? ? ? ? 棧和隊列:
? ? ? ? ? ? ? ? 棧同樣是最基礎的數據結構,只能從一端訪問的線性群體,可訪問的為棧頂,另一端為棧底,后進先出。表達式處理方法可用棧數據結構。
? ? ? ? ? ? ? ? 棧的基本狀態分為:棧空、棧滿、一般狀態。
? ? ? ? ? ? ? ? 棧的基本操作:初始化、入棧、出棧、清空棧、訪問棧頂元素、檢測棧的狀態。
? ? ? ? ? ? ? ? 隊列只能在一端添加元素,從另一端刪除元素。隊列狀態有:隊空、隊滿、一般狀態。
9.3 群體數據組織
? ? ? ? 這節主要介紹了數據的排序方法,這是我們算法和數據結構課的基礎內容了,哈哈!主要有插入排序、選擇排序、交換排序、順序查找、折半查找。排序的基礎操作就是比較和交換。
9.4 深度探索
? ? ? ? 模版實例化機制
? ? ? ? ? ? ? ? 1. 模版與模版實例
? ? ? ? ? ? ? ? 2. 隱含實例化
? ? ? ? ? ? ? ? 3. 多文件結構中的模版的組織
? ? ? ? ? ? ? ? 4. 顯示實例化
? ? ? ? 為模版定義特殊的實現
? ? ? ? ? ? ? ? 1. 模版的特化
? ? ? ? ? ? ? ? 2. 類模版的偏特化
? ? ? ? ? ? ? ? 3. 函數模版的重載
第十章 泛型程序設計
? ? ? ? 泛型程序的設計使程序不依賴數據結構,模版是泛型程序設計的主要工具。
? ? ? ? STL有六大組件:分別為容器,算法,迭代器,仿函數,適配器,配置器。
????????
????????????????1.容器( containers): 各種數據結構,如vector, list, deque, set, map,用來存放數據, STL 容器是一種 class template。容器可分為順序容器和關聯容器。
? ? ? ? ? ? ? ? 下圖為STL容器的頭文件及所屬概念:
????????????????2.算法( algorithms): 各種常用算法如sort, search, copy, erase等, STL 算法是一種 function template。
????????????????3.迭代器( iterators): 扮演容器與算法之間的膠著劑,是所謂的「泛型指標」。共有五種類型,以及其它衍生變化。迭代器是一種將operator*, operator->, operator++, operator--等指針相關操作予以多元化的 class template。所有STL容器都附帶有自己專屬的迭代器,只有容器設計者才知道如何巡訪自己的元素。原生指針( nativepointer)也是一種迭代器。
????????????????4.仿函數( functors): 行為類似函數,可做為算法的某種策略( policy)。仿函數是一種重載了 operator()的 class 或class template,一般函數指針可視為狹義的仿函數。
????????????????5.適配器( adapters): 一種用來修飾容器( containers)或仿函式( functors)或迭代器( iterators)接口的東西。例如 STL 提供的 queue 和stack,雖然看似容器,其實只能算是一種容器適配器,因為它們的底部完全借重 deque,所有動作都由底層的 deque供應。改變functor接口者,稱為function adapter,改變container接口者,稱為container adapter,改變iterator界面者,稱為iterator adapter。
????????????????6.配置器( allocators): 負責空間配置與管理,配置器是一個實現了動態空間配置、空間管理、空間釋放的 class template。
????????
這里面推薦繼續閱讀候捷的《STL源碼剖析》,里面講了各種C++函數的實現方式。
第十一章 流類庫與輸入輸出
11.1 IO流的概念及流類庫的結構
? ? ? ? 流是一種抽象,負責在數據的生產者和消費者間建立聯系,管理數據的流動。對程序而言,文件有的特性流對象同樣有,程序將流對象看做文件對象的化身。
? ? ? ? 流類的層次圖如下:? ? ? ? ?
11.2 輸出流??
????????最重要的三個輸出流:
? ? ? ? ? ? ? ? 1. ostream
? ? ? ? ? ? ? ? 2. ofstream
? ? ? ? ? ? ? ? 3. ostringstream
? ? ? ? 預先定義的輸出流對象:
? ? ? ? ? ? ? ? 1. cout標準輸出流
? ? ? ? ? ? ? ? 2. cerr標準錯誤輸出流
? ? ? ? ? ? ? ? 3. clog類似于cerr,但是有緩沖,緩沖區滿時被輸出。
? ? ? ? 構造輸出流對象:
? ? ? ? ? ? ? ? ofstream支持磁盤文件輸出,在構造函數中指定一個文件名,當構造這個文件時,文件是自動打開的:
? ? ? ? ? ? ? ? ????????ofstram myFile("filename");
? ? ? ? ? ? ? ? 可以調用默認構造函數后使用open成員函數打開文件。
? ? ? ? ? ? ? ? ? ? ? ? ofstream myFile; //聲明一個靜態文件輸出流對象
? ? ? ? ? ? ? ? ? ? ? ? myFile.open("filename") //打開文件,使流對象與文件建立聯系。
? ? ? ? ? ? ? ? 同樣可以在構造或者open打開文件時指定模式。
? ? ? ? ? ? ? ? ? ? ? ? ostream myFile("filename",ios_base::out | ios_base::binary);
? ? ? ? 使用插入運算符和操縱符來控制輸出格式,如輸出寬度、對其方式、精度等。
? ? ? ? 文件輸出流成員函數:
? ? ? ? ? ? ? ? open put write?
? ? ? ? ? ? ? ? seekp tellp:操作文件流內部指針。
? ? ? ? ? ? ? ? close
? ? ? ? ? ? ? ? 錯誤處理函數
? ? ? ?
????????????????
????????
????????????????
????????????????
總結
以上是生活随笔為你收集整理的C++基础课—郑莉9-的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux 日志管理
- 下一篇: 基于Netty的分布式聊天系统