【OOP】C++自定義類型的迭代器

来源:https://www.cnblogs.com/bljw-02/archive/2022/05/12/16264952.html
-Advertisement-
Play Games

C++自定義迭代器:介紹了【什麼時候需要用到自定義迭代器】和【如何實現自定義迭代器】。 ...


目錄


1. 什麼時候需要使用自定義的迭代器?

常見、基本的數組類型

  • 對於常見、基本的數組類型,如:intchar ,我們可以簡單地使用下標來進行遍歷:

    int array[5] = {1,2,3,4,5};
    
    // 方法1:使用下標遍歷
    for (int ind = 0; ind < 5; ++ind) {
        cout << array[ind] << " ";
    }
    

    也可以使用範圍來進行遍歷,達到和使用下標同樣的遍歷效果:

    // 方法2:使用範圍遍歷
    for (int &n: array) {
        cout << n << " ";
    }
    

回到頂部

STL 容器

  • 對於 STL 容器來說,如:vectorlist ,我們同樣也可以使用下標和範圍來進行遍歷:

    vector<int> vec = {1,2,3,4,5};
    
    // 方法1:使用下標遍歷
    for (int ind = 0; ind < vec.size(); ++ind) {
        cout << vec[ind] << " ";
    }
    
    // 方法2:使用範圍遍歷
    for (int &n: vec) {
        cout << n << " ";
    }
    

    除了以上兩種方法,STL 容器還可以使用迭代器(iterator)進行遍歷:

    vector<int>::iterator iter;
    
    // 方法3:使用迭代器遍歷
    // .begin() 是指向 vector 首元素的位置的迭代器
    // .end() 是指向 vector 最後一個元素的位置的下一個位置的迭代器
    for (iter = vec.begin(); iter != vec.end(); ++iter) {
        cout << *iter << " ";
    }
    

回到頂部

自定義數據類型

  • 下麵給出一個簡單的自定義類:

    class Group {
    private:
    	vector<vector<int>> students_marks;
        ......
    }
    

    其中,students_marks 是一個用來記錄學生若幹次的分數的 vector,students_marks[0] 也是一個 vector,用來記錄第一個學生的分數,其中 students_marks[0][0] 表示第一個學生的第一個分數。

  • 如果要對 students_marks 進行遍歷,由於不存在 vector<int> 類型的迭代器,因此方法2和方法3無法使用,只能使用下標遍曆法:

    // 定義一個函數,用來輸出 vector 中所有元素
    void printvec(vector<int> &vec) {
        for(int ind = 0; ind < vec.size(); ++ind) {
            cout << vec[ind] << " ";
        }
    }
    
    // 使用下標對 vector<int> 類型的元素進行遍歷
    for (int ind = 0; ind < students_marks.size(); ++ind) {
        printvec(students_marks[ind]);
    }
    
  • 如果要使用以下方法對 students_marks 進行遍歷:

    // 定義 Group 類型的 G
    Group G;
    
    // 使用範圍遍歷
    for(auto v: G) {
        printvec(v);
    }
    

    則需要自己手動編寫指向 vector<int> 數據類型的迭代器。

回到頂部


2. 開始編寫自定義迭代器之前需要思考的問題

  1. 迭代器進行遍歷的對象是什麼?
  2. 迭代器遍歷的範圍是什麼?
  3. 迭代器指向的數據是什麼類型?

只要想明白這三個問題,就不難實現自定義類型的迭代器。

以上面的類 Group 為例,

我們想遍歷的是 students_marks ,將每個學生的分數輸出。

對應問題1,迭代器遍歷的對象是 vector<vector<int>> students_marks

對應問題2,假設總共有 k 個學生,則 students_marks.size() = k ,遍歷的範圍是從 students_marks[0]students_marks[k-1]

對應問題3,迭代器指向的數據是 students_marks[x] ,類型是 vector<int>

回到頂部


3. 如何編寫及實現自定義類型的迭代器?

在後面的步驟中,一些常用的名詞將會以以下標識符代稱:

代替的標識符 對應上面的例子是
遍歷的對象 OBJECT students_marks
遍歷對象的數據類型 OBJECT_type vector<vector<int>>
遍歷對象所處類 OBJECT_class Group
迭代器指向的數據 VALUE students_marks[x]
迭代器指向的數據類型 VALUE_type vector<int>

回到頂部

  1. object 所處的 class 中定義一個迭代器(iterator)的結構體(struct):

    class OBJECT_class {
    private:
    	OBJECT_type OBJECT;
        
    public:
        struct Iterator {
            
        }
        
        ......
    }
    

  2. 設定迭代器的屬性:

    struct Iterator {
        using iterator_category = std::forward_iterator_tag;
        using difference_type = std::ptrdiff_t;
        using value_type = VALUE_type;
        using reference = const VALUE_type&;
        using pointer = VALUE_type*;
    }
    
    • iterator_category 是迭代器的類型,如果是正常、基礎的情況下,選擇 forward_iterator_tag 就可以了
    • difference_type 選擇 ptrdiff_t
    • 其餘的 value_typereferencepointer 都是自定義的,根據實際情況填寫

  3. 定義迭代器的成員變數、構造函數、基礎函數

    struct Iterator {
        using iterator_category = std::forward_iterator_tag;
        using difference_type = std::ptrdiff_t;
        using value_type = VALUE_type;
        using reference = const VALUE_type&;
        using pointer = VALUE_type*;
        
        // 構造函數
        Iterator(pointer p) :ptr(p) {}
        
        // 拷貝賦值函數
        Iterator& operator=(const Iterator& it) {
            ptr = it.ptr;
        }
        
        // 等於運算符
        bool operator==(const Iterator& it) const {
            return ptr == it.ptr;
        }
        
        // 不等於運算符
        bool operator!=(const Iterator& it) const {
            return ptr != it.ptr;
        }
        
        // 首碼自加
        Iterator& operator++() {
            ptr++;
            return *this;
        }
        
        // 尾碼自加
        Iterator operator ++(int) {
            Iterator tmp = *this;
            ++(*this);
            return tmp;
        }
        
        // 首碼自減
        Iterator& operator--() {
            ptr--;
            return *this;
        }
        
        // 尾碼自減
        Iterator operator --(int) {
            Iterator tmp = *this;
            --(*this);
            return tmp;
        }
        
        // 取值運算
        VALUE_type& operator*() {
            return *ptr;
        }
        
    private:
        // 定義一個指針
        pointer ptr; 
    }
    
    • 以上的函數不是必要也不是完整的,如果不需要用到的可以不寫,額外需要用到的函數可以自行編寫。
    • 但是在大多數情況下,上面這些函數基本上足矣。

  4. 設定遍歷的範圍:

    class OBJECT_class {
    private:
    	OBJECT_type OBJECT;
        
    public:
        struct Iterator {
            
            ......
            ......
                
        private:
            pointer ptr;
            
        }
        
        // 遍歷的第一個元素的位置
        Iterator begin() {
            VALUE_type* head = &OBJECT[0];
            return Iterator(head);
        }
        
        // 遍歷的最後一個元素的下一個位置
        Iterator end() {
            VALUE_type* head = &OBJECT[0];
            return Iterator(head + OBJECT.size());
        }
        
        ......
    }
    
    • head 是指向第一個 VALUE 的指針

回到頂部


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、引言 SQL Server有一些很好用的功能,只不過由於個人原因沒用過或者不記得怎麼用,導致需要花點時間用其它方式來實現。 二、好用小知識 2.1、FORMAT函數 1)時間格式化,如將當前日期格式化為2022-05-12: SELECT FORMAT(GETDATE(),'yyyy-MM-dd ...
  • 一、引言 A表數據同步至B表的場景很常見,比如一個公司有總部及分廠,它們使用相同的系統,只是賬套不同。此時,一些基礎數據如物料信息,只需要總部錄入即可,然後間隔一定時間同步至分廠,避免了重覆工作。 二、測試數據 CREATE TABLE StudentA ( ID VARCHAR(32), Name ...
  • 本文介紹什麼是 SQL 的聚集函數,如何利用它們彙總表的數據。這些函數很高效,它們返回結果一般比你在自己的客戶端應用程式中計算要快得多。 一、聚集函數 我們經常需要彙總數據而不用把它們實際檢索出來,為此 SQL 提供了專門的函數。使用這些函數,SQL 查詢可用於檢索數據,以便分析和報表生成。這種類型 ...
  • 本文介紹什麼是函數,DBMS 支持何種函數,以及如何使用這些函數;還將講解為什麼 SQL 函數的使用可能會帶來問題。 一、函數 與大多數其他電腦語言一樣,SQL 也可以用函數來處理數據。函數一般是在數據上執行的,為數據的轉換和處理提供了方便。 SQL 如何創建計算欄位 中用來去掉字元串尾的空格的 ...
  • 本文介紹什麼是計算欄位,如何創建計算欄位,我們用例子說明瞭計算欄位在字元串拼接和算術計算中的用途。以及如何從應用程式中使用別名引用它們。 一、計算欄位 存儲在資料庫表中的數據一般不是應用程式所需要的格式,下麵舉幾個例子。 需要顯示公司名,同時還需要顯示公司的地址,但這兩個信息存儲在不同的表列中。 城 ...
  • 轉載請標明出處,維權必究: https://www.cnblogs.com/tangZH/p/12543154.html Glide作為一個強大的圖片載入框架,已經被android官方使用,所以,明白Glide的載入流程以及原理對加深我們對glide的理解是很重要的。 本文基於glide 4.11 ...
  • 在 OpenHarmony 生態發展過程中,涌現了大批優秀的代碼貢獻者,本專題旨在表彰貢獻、分享經驗,文中內容來自嘉賓訪談,不代表 OpenHarmony 工作委員會觀點。 ...
  • Vue3使用插槽時的父子組件傳值 用法見官方文檔深入組件章節,插槽部分: 參考文檔:插槽-作用域插槽-插槽prop 作用域插槽 有時讓插槽內容能夠訪問子組件中才有的數據是很有用的。 需求:插槽內容能夠訪問子組件中才有的數據 實現 子組件 TodoList.vue <template> <div v- ...
一周排行
    -Advertisement-
    Play Games
  • Dapr Outbox 是1.12中的功能。 本文只介紹Dapr Outbox 執行流程,Dapr Outbox基本用法請閱讀官方文檔 。本文中appID=order-processor,topic=orders 本文前提知識:熟悉Dapr狀態管理、Dapr發佈訂閱和Outbox 模式。 Outbo ...
  • 引言 在前幾章我們深度講解了單元測試和集成測試的基礎知識,這一章我們來講解一下代碼覆蓋率,代碼覆蓋率是單元測試運行的度量值,覆蓋率通常以百分比表示,用於衡量代碼被測試覆蓋的程度,幫助開發人員評估測試用例的質量和代碼的健壯性。常見的覆蓋率包括語句覆蓋率(Line Coverage)、分支覆蓋率(Bra ...
  • 前言 本文介紹瞭如何使用S7.NET庫實現對西門子PLC DB塊數據的讀寫,記錄了使用電腦模擬,模擬PLC,自至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1.Windows環境下鏈路層網路訪問的行業標準工具(WinPcap_4_1_3.exe)下載鏈接:http ...
  • 從依賴倒置原則(Dependency Inversion Principle, DIP)到控制反轉(Inversion of Control, IoC)再到依賴註入(Dependency Injection, DI)的演進過程,我們可以理解為一種逐步抽象和解耦的設計思想。這種思想在C#等面向對象的編 ...
  • 關於Python中的私有屬性和私有方法 Python對於類的成員沒有嚴格的訪問控制限制,這與其他面相對對象語言有區別。關於私有屬性和私有方法,有如下要點: 1、通常我們約定,兩個下劃線開頭的屬性是私有的(private)。其他為公共的(public); 2、類內部可以訪問私有屬性(方法); 3、類外 ...
  • C++ 訪問說明符 訪問說明符是 C++ 中控制類成員(屬性和方法)可訪問性的關鍵字。它們用於封裝類數據並保護其免受意外修改或濫用。 三種訪問說明符: public:允許從類外部的任何地方訪問成員。 private:僅允許在類內部訪問成員。 protected:允許在類內部及其派生類中訪問成員。 示 ...
  • 寫這個隨筆說一下C++的static_cast和dynamic_cast用在子類與父類的指針轉換時的一些事宜。首先,【static_cast,dynamic_cast】【父類指針,子類指針】,兩兩一組,共有4種組合:用 static_cast 父類轉子類、用 static_cast 子類轉父類、使用 ...
  • /******************************************************************************************************** * * * 設計雙向鏈表的介面 * * * * Copyright (c) 2023-2 ...
  • 相信接觸過spring做開發的小伙伴們一定使用過@ComponentScan註解 @ComponentScan("com.wangm.lifecycle") public class AppConfig { } @ComponentScan指定basePackage,將包下的類按照一定規則註冊成Be ...
  • 操作系統 :CentOS 7.6_x64 opensips版本: 2.4.9 python版本:2.7.5 python作為腳本語言,使用起來很方便,查了下opensips的文檔,支持使用python腳本寫邏輯代碼。今天整理下CentOS7環境下opensips2.4.9的python模塊筆記及使用 ...