你們都知道C++中類的成員函數默認都提供了this指針,在非靜態成員函數中當你調用函數的時候,編譯器都會「自動」幫你把這個this指針加到函數形參裏去。固然在C++靈活性下面,類還具有了靜態成員和靜態函數,即函數
class A { public: static void test() { m_staticA += 1; } private: static int m_staticA; int m_a };
此時你的test函數只能去訪問m_staticA成員,而不能去訪問m_a。同窗可能會問,這算什麼問題?問題都是在應用場景中才能體現的,我一開始也是不覺得意,直到我遇到了回調函數這個煩人的問題我才真正靜下心來去考慮這個知識點。this
先簡單說下回調,在座的應該都知道回調的含義,在C中回調主要體現就是回調函數,固然C++中也有仿函數等其餘用法,拋開這些,單純在回調函數這個點上咱們進行以下討論。spa
因爲C++類的成員函數都隱含了this指針,若是我直接註冊,好比指針
typedef void (A::*FunPtr)(); FunPtr p = A::hello; p();
此時程序會報錯,提示信息是你缺乏一個this指針,意味着你要真的想使用p,你必須有一個分配好空間的實例才能來調用code
typedef void (A::*FunPtr)(); FunPtr p = A::hello; A a; A *pA = new A(); (a.*p)(); (pA->*p)();
固然,若是僅僅是對C++的類靜態函數進行回調函數註冊,你是不須要考慮this指針的blog
typedef void (A::*FunPtr)(); FunPtr p = A::test; p();
但問題就是,你此時的靜態函數是不能擁有你的成員變量的,看到了吧,問題來了。面對這種需求,咱們就真正應該靜下心來好好想一想,究竟如何才能讓靜態函數去訪問非靜態成員變量這個問題了。接口
方法一:內存
有一個很取巧的辦法,就是在靜態函數的形參表裏加上實例的地址,也就是編譯器
class A { public: static void test(A *a) { a->m_a += 1; } void hello() { } private: static int m_staticA; int m_a };
這樣在你回調函數的時候,你能夠經過這個來讓自己不能訪問成員非靜態變量的靜態函數(太拗口)來訪問非靜態成員變量。回調函數
方法二:
其實這個方法在GLIB中用的不少,就是放上全局變量地址即
A g_a; class A { public: static void test() { g_a.m_a += 1; } void hello() { } private: static int m_staticA; int m_a };
這種方法咱們瞭解就好,全局變量咱們並不推薦。
方法三:
你們都知道靜態成員函數不能訪問非靜態成員,但別忘了,他們能夠訪問靜態成員,也就是說,若是咱們的這個類是個單例,咱們徹底能夠在建立的時候把this指針賦值給那個靜態成員,而後在靜態成員函數內部就能夠放心大膽的使用了。
class A { public: A() { m_gA = this; } static void test() { m_gA.m_a += 1; } void hello() { } private: static int m_staticA; static A *m_gA; int m_a };
方法四:
和方法一比較像,但他的方向思想更多的是針對內存塊這個概念,意思就是在靜態函數的形參比加上一個void *的內存首地址,而後在內部作轉換
class A { public: static void test(void *pData) { A *a = (A *)pData; a->m_a += 1; } void hello() { } private: static int m_staticA; int m_a }; A a; test(&a);
如上,我整理了4種方法,固然方法還有不少,其實繞了這麼大遠路,咱們的但願就是不破壞回調函數整潔的函數接口(加上本身的實例指針)而作的妥協,若是你更喜歡經過改變接口或者經過用Java相似的interface方式來實現,那也沒有問題,這裏主要就是提供給你們一個思路,C++確實很靈活,咱們要用好這把雙刃劍 : )