成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

C++ 類成員函數指針語法的友好指南

開發 后端
如果你正在尋找性能、復雜性或許多可能的解決方法來解決問題,那么在涉及到極端的情況下,C++ 總是一個很好的選擇。當然,功能通常伴隨著復雜性,但是一些 C++ 的特性幾乎難以分辨。根據我的觀點,C++ 的 類成員函數指針 也許是我接觸過的最復雜的表達式,但是我會先從一些較簡單的開始。

[[406338]]

一旦你理解了一般原則,C++ 類成員函數指針不再那么令人生畏。

如果你正在尋找性能、復雜性或許多可能的解決方法來解決問題,那么在涉及到極端的情況下,C++ 總是一個很好的選擇。當然,功能通常伴隨著復雜性,但是一些 C++ 的特性幾乎難以分辨。根據我的觀點,C++ 的 類成員函數指針 也許是我接觸過的最復雜的表達式,但是我會先從一些較簡單的開始。

文章中的例子可以在我的 Github 倉庫 里找到。

C 語言:函數指針

讓我們先從一些基礎開始:假設你有一個函數接收兩個整數作為參數返回一個整數:

  1. int sum(int a, int b) {
  2. return a+b;
  3. }

在純 C 語言中,你可以創建一個指向這個函數的指針,將其分配給你的 sum(...) 函數,通過解引用來調用它。函數的簽名(參數、返回類型)必須符合指針的簽名。除此之外,一個函數指針表現和普通的指針相同:

  1. int (*funcPtrOne)(int, int);
  2.  
  3. funcPtrOne = ∑
  4.  
  5. int resultOne = funcPtrOne(2, 5);

如果你使用指針作為參數并返回一個指針,這會顯得很丑陋:

  1. int *next(int *arrayOfInt){
  2. return ++arrayOfInt;
  3. }
  4.  
  5. int *(*funcPtrTwo)(int *intPtr);
  6.  
  7. funcPtrTwo = &next;
  8.  
  9. int resultTwo = *funcPtrTwo(&array[0]);

C 語言中的函數指針存儲著子程序的地址。

指向類成員函數的指針

讓我們來進入 C++:好消息是你也許不需要使用類成員函數指針,除非在一個特別罕見的情況下,比如說接下來的例子。首先,你已經知道定義一個類和其中一個成員函數:

  1. class MyClass
  2. {
  3. public:
  4.  
  5. int sum(int a, int b) {
  6. return a+b;
  7. }
  8.  
  9. };

1、定義一個指針指向某一個類中一個成員函數

聲明一個指針指向 MyClass 類成員函數。在此時,你并不知道想調用的具體函數。你僅僅聲明了一個指向 MyClass 類中任意成員函數的指針。當然,簽名(參數、返回值類型)需要匹配你接下想要調用的 sum(...) 函數:

  1. int (MyClass::*methodPtrOne)(int, int);

2、賦值給一個具體的函數

為了和 C 語言(或者 靜態成員函數)對比,類成員函數指針不需要指向絕對地址。在 C++ 中,每一個類中都有一個虛擬函數表(vtable)用來儲存每個成員函數的地址偏移量。一個類成員函數指針指向 vtable 中的某個條目,因此它也只存儲偏移值。這樣的原則使得 多態 變得可行。

因為 sum(...) 函數的簽名和你的指針聲明匹配,你可以賦值簽名給它:

  1. methodPtrOne = &MyClass::sum;

3、調用成員函數

如果你想使用指針調用一個類成員函,你必須提供一個類的實例:

  1. MyClass clsInstance;
  2. int result = (clsInstance.*methodPtrOne)(2,3);

你可以使用 . 操作符來訪問,使用 * 對指針解引用,通過提供兩個整數作為調用函數時的參數。這是丑陋的,對吧?但是你可以進一步應用。

在類內使用類成員函數指針

假設你正在創建一個帶有后端和前端的 客戶端/服務器 原理架構的應用程序。你現在并不需要關心后端,相反的,你將基于 C++ 類的前端。前端依賴于后端提供的數據完成初始化,所以你需要一個額外的初始化機制。同時,你希望通用地實現此機制,以便將來可以使用其他初始化函數(可能是動態的)來拓展你的前端。

首先定義一個數據類型用來存儲初始化函數(init)的指針,同時描述何時應調用此函數的信息(ticks):

  1. template<typename T>
  2. struct DynamicInitCommand {
  3. void (T::*init)(); // 指向額外的初始化函數
  4. unsigned int ticks; // 在 init() 調用后 ticks 的數量
  5. };

下面一個 Frontend 類示例代碼:

  1. class Frontend
  2. {
  3. public:
  4.  
  5. Frontend(){
  6. DynamicInitCommand<Frontend> init1, init2, init3;
  7.  
  8. init1 = { &Frontend::dynamicInit1, 5};
  9. init2 = { &Frontend::dynamicInit2, 10};
  10. init3 = { &Frontend::dynamicInit3, 15};
  11.  
  12. m_dynamicInit.push_back(init1);
  13. m_dynamicInit.push_back(init2);
  14. m_dynamicInit.push_back(init3);
  15. }
  16. void tick(){
  17. std::cout << "tick: " << ++m_ticks << std::endl;
  18. /* 檢查延遲初始化 */
  19. std::vector<DynamicInitCommand<Frontend>>::iterator it = m_dynamicInit.begin();
  20.  
  21. while (it != m_dynamicInit.end()){
  22. if (it->ticks < m_ticks){
  23. if(it->init)
  24. ((*this).*(it->init))(); // 這里是具體調用
  25.  
  26. it = m_dynamicInit.erase(it);
  27.  
  28. } else {
  29. it++;
  30. }
  31. }
  32. }
  33. unsigned int m_ticks{0};
  34. private:
  35.  
  36. void dynamicInit1(){
  37. std::cout << "dynamicInit1 called" << std::endl;
  38. };
  39.  
  40. void dynamicInit2(){
  41. std::cout << "dynamicInit2 called" << std::endl;
  42. }
  43.  
  44. void dynamicInit3(){
  45. std::cout << "dynamicInit3 called" << std::endl;
  46. }
  47.  
  48. unsigned int m_initCnt{0};
  49. std::vector<DynamicInitCommand<Frontend> > m_dynamicInit;
  50. };

在 Frontend 完成實例化后,tick() 函數會被后端以固定的時間時間調用。例如,你可以每 200 毫秒調用一次:

  1. int main(int argc, char* argv[]){
  2. Frontend frontendInstance;
  3.  
  4. while(true){
  5. frontendInstance.tick(); // 僅用于模擬目的
  6. std::this_thread::sleep_for(std::chrono::milliseconds(200));
  7. }
  8. }

Fronted 有三個額外的初始化函數,它們必須根據 m_ticks 的值來選擇調用哪個。在 ticks 等于何值調用哪個初始化函數的信息存儲在數組 m_dynamicInit 中。在構造函數(Frontend())中,將此信息附加到數組中,以便在 5、10 和 15 個 tick 后調用其他初始化函數。當后端調用 tick() 函數時,m_ticks 值會遞增,同時遍歷數組 m_dynamicInit 以檢查是否必須調用初始化函數。

如果是這種情況,則必須通過引用 this 指針來取消引用成員函數指針:

  1. ((*this).*(it->init))()

總結

如果你并不熟悉類成員函數指針,它們可能會顯得有些復雜。我做了很多嘗試和經歷了很多錯誤,花了一些時間來找到正確的語法。然而,一旦你理解了一般原理后,方法指針就變得不那么可怕了。

這是迄今為止我在 C++ 中發現的最復雜的語法。

 

責任編輯:龐桂玉 來源: Linux中國
相關推薦

2010-02-02 15:01:59

C++成員函數指針

2011-07-20 16:09:08

C++

2009-05-26 09:31:00

C++重載覆蓋

2010-01-18 18:04:28

靜態成員

2024-02-22 18:07:17

C++靜態成員代碼

2010-01-21 14:28:03

C++靜態成員函數

2010-01-19 18:35:12

靜態成員

2010-02-02 10:07:59

C++全局函數

2010-02-01 17:31:06

C++類成員

2023-11-22 13:22:51

C++函數

2011-04-11 11:09:50

this指針

2010-01-18 15:53:27

C++析構函數

2016-12-26 09:23:18

C++函數覆蓋

2010-01-21 09:34:57

C++語法

2010-02-06 09:31:42

C++函數對象

2011-07-20 17:54:02

C++

2024-12-30 11:12:59

C++靜態成員函數

2021-12-21 15:31:10

C++語言指針

2010-02-04 10:08:00

C++靜態成員函數

2011-07-12 11:15:46

C++
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: av手机免费在线观看 | 999精品视频 | 久久久久久久久国产精品 | 午夜免费福利片 | 成人av看片 | 日本一区二区三区四区 | 午夜欧美 | 九九精品热 | 亚州精品天堂中文字幕 | 国产最好的av国产大片 | 久久青青| 三区在线观看 | 欧洲一区二区在线 | 免费在线黄 | 免费观看成人鲁鲁鲁鲁鲁视频 | 久久久国产一区二区三区四区小说 | 特级黄色毛片 | 日韩久久久久久 | 亚洲欧美在线观看 | 91在线一区二区三区 | 日韩欧美一二三区 | 国产亚洲精品美女久久久久久久久久 | 一级大片网站 | 在线午夜 | 九色在线视频 | 精品欧美乱码久久久久久1区2区 | 久久精品国产亚洲一区二区 | 中文天堂在线一区 | 美女一级黄 | 国产一区二区三区 | 国产精品成人一区 | 男人的天堂中文字幕 | 黄色大片网站 | 一区二区三区视频在线 | av在线天天 | 91精品国产色综合久久 | 一区二区中文字幕 | 丝袜 亚洲 另类 欧美 综合 | 国产一区二区欧美 | 亚洲精品自在在线观看 | 久久精品一区二区三区四区 |