日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
C++類成員函數(shù)指針語(yǔ)法的友好指南

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

創(chuàng)新互聯(lián)專注于企業(yè)營(yíng)銷型網(wǎng)站建設(shè)、網(wǎng)站重做改版、雙灤網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、H5建站、購(gòu)物商城網(wǎng)站建設(shè)、集團(tuán)公司官網(wǎng)建設(shè)、外貿(mào)網(wǎng)站建設(shè)、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁(yè)設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為雙灤等各大城市提供網(wǎng)站開(kāi)發(fā)制作服務(wù)。

如果你正在尋找性能、復(fù)雜性或許多可能的解決方法來(lái)解決問(wèn)題,那么在涉及到極端的情況下,C++ 總是一個(gè)很好的選擇。當(dāng)然,功能通常伴隨著復(fù)雜性,但是一些 C++ 的特性幾乎難以分辨。根據(jù)我的觀點(diǎn),C++ 的 類成員函數(shù)指針 也許是我接觸過(guò)的最復(fù)雜的表達(dá)式,但是我會(huì)先從一些較簡(jiǎn)單的開(kāi)始。

文章中的例子可以在我的 Github 倉(cāng)庫(kù) 里找到。

C 語(yǔ)言:函數(shù)指針

讓我們先從一些基礎(chǔ)開(kāi)始:假設(shè)你有一個(gè)函數(shù)接收兩個(gè)整數(shù)作為參數(shù)返回一個(gè)整數(shù):

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

在純 C 語(yǔ)言中,你可以創(chuàng)建一個(gè)指向這個(gè)函數(shù)的指針,將其分配給你的 sum(...) 函數(shù),通過(guò)解引用來(lái)調(diào)用它。函數(shù)的簽名(參數(shù)、返回類型)必須符合指針的簽名。除此之外,一個(gè)函數(shù)指針表現(xiàn)和普通的指針相同:

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

如果你使用指針作為參數(shù)并返回一個(gè)指針,這會(huì)顯得很丑陋:

  
 
 
  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 語(yǔ)言中的函數(shù)指針存儲(chǔ)著子程序的地址。

指向類成員函數(shù)的指針

讓我們來(lái)進(jìn)入 C++:好消息是你也許不需要使用類成員函數(shù)指針,除非在一個(gè)特別罕見(jiàn)的情況下,比如說(shuō)接下來(lái)的例子。首先,你已經(jīng)知道定義一個(gè)類和其中一個(gè)成員函數(shù):

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

1、定義一個(gè)指針指向某一個(gè)類中一個(gè)成員函數(shù)

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

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

2、賦值給一個(gè)具體的函數(shù)

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

因?yàn)?nbsp;sum(...) 函數(shù)的簽名和你的指針聲明匹配,你可以賦值簽名給它:

  
 
 
  1. methodPtrOne = &MyClass::sum;

3、調(diào)用成員函數(shù)

如果你想使用指針調(diào)用一個(gè)類成員函,你必須提供一個(gè)類的實(shí)例:

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

你可以使用 . 操作符來(lái)訪問(wèn),使用 * 對(duì)指針解引用,通過(guò)提供兩個(gè)整數(shù)作為調(diào)用函數(shù)時(shí)的參數(shù)。這是丑陋的,對(duì)吧?但是你可以進(jìn)一步應(yīng)用。

在類內(nèi)使用類成員函數(shù)指針

假設(shè)你正在創(chuàng)建一個(gè)帶有后端和前端的 客戶端/服務(wù)器 原理架構(gòu)的應(yīng)用程序。你現(xiàn)在并不需要關(guān)心后端,相反的,你將基于 C++ 類的前端。前端依賴于后端提供的數(shù)據(jù)完成初始化,所以你需要一個(gè)額外的初始化機(jī)制。同時(shí),你希望通用地實(shí)現(xiàn)此機(jī)制,以便將來(lái)可以使用其他初始化函數(shù)(可能是動(dòng)態(tài)的)來(lái)拓展你的前端。

首先定義一個(gè)數(shù)據(jù)類型用來(lái)存儲(chǔ)初始化函數(shù)(init)的指針,同時(shí)描述何時(shí)應(yīng)調(diào)用此函數(shù)的信息(ticks):

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

下面一個(gè) Frontend 類示例代碼:

  
 
 
  1. class Frontend
  2. {
  3. public:
  4.  
  5. Frontend(){
  6. DynamicInitCommand 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>::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))(); // 這里是具體調(diào)用
  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 > m_dynamicInit;
  50. };

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

  
 
 
  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 有三個(gè)額外的初始化函數(shù),它們必須根據(jù) m_ticks 的值來(lái)選擇調(diào)用哪個(gè)。在 ticks 等于何值調(diào)用哪個(gè)初始化函數(shù)的信息存儲(chǔ)在數(shù)組 m_dynamicInit 中。在構(gòu)造函數(shù)(Frontend())中,將此信息附加到數(shù)組中,以便在 5、10 和 15 個(gè) tick 后調(diào)用其他初始化函數(shù)。當(dāng)后端調(diào)用 tick() 函數(shù)時(shí),m_ticks 值會(huì)遞增,同時(shí)遍歷數(shù)組 m_dynamicInit 以檢查是否必須調(diào)用初始化函數(shù)。

如果是這種情況,則必須通過(guò)引用 this 指針來(lái)取消引用成員函數(shù)指針:

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

總結(jié)

如果你并不熟悉類成員函數(shù)指針,它們可能會(huì)顯得有些復(fù)雜。我做了很多嘗試和經(jīng)歷了很多錯(cuò)誤,花了一些時(shí)間來(lái)找到正確的語(yǔ)法。然而,一旦你理解了一般原理后,方法指針就變得不那么可怕了。

這是迄今為止我在 C++ 中發(fā)現(xiàn)的最復(fù)雜的語(yǔ)法。


名稱欄目:C++類成員函數(shù)指針語(yǔ)法的友好指南
URL分享:http://www.dlmjj.cn/article/dhppicg.html