大家都知道C++中类的成员函数默认都提供了this指针,在非静态成员函数中当你调用函数的时候,编译器都会“自动”帮你把这个this指针加到函数形参里去。当然在C++灵活性下面,类还具备了静态成员和静态函数,即

class A
{
public:
static void test()
{
m_staticA += ;
}
private:
static int m_staticA;
int m_a
};

此时你的test函数只能去访问m_staticA成员,而不能去访问m_a。同学可能会问,这算什么问题?问题都是在应用场景中才能体现的,我一开始也是不以为意,直到我遇到了回调函数这个烦人的问题我才真正静下心来去考虑这个知识点。

先简单说下回调,在座的应该都知道回调的含义,在C中回调主要体现就是回调函数,当然C++中也有仿函数等其他用法,抛开这些,单纯在回调函数这个点上我们进行如下讨论。

由于C++类的成员函数都隐含了this指针,如果我直接注册,比如

typedef void (A::*FunPtr)();
FunPtr p = A::hello;
p();

此时程序会报错,提示信息是你缺少一个this指针,意味着你要真的想使用p,你必须有一个分配好空间的实例才能来调用

typedef void (A::*FunPtr)();
FunPtr p = A::hello; A a;
A *pA = new A(); (a.*p)();
(pA->*p)();

当然,如果仅仅是对C++的类静态函数进行回调函数注册,你是不需要考虑this指针的

typedef void (A::*FunPtr)();
FunPtr p = A::test;
p();

但问题就是,你此时的静态函数是不能拥有你的成员变量的,看到了吧,问题来了。面对这种需求,我们就真正应该静下心来好好想想,究竟如何才能让静态函数去访问非静态成员变量这个问题了。

方法一:

有一个很取巧的办法,就是在静态函数的形参表里加上实例的地址,也就是

class A
{
public:
static void test(A *a)
{
a->m_a += ;
}
void hello()
{
}
private:
static int m_staticA;
int m_a
};

这样在你回调函数的时候,你可以通过这个来让本身不能访问成员非静态变量的静态函数(太拗口)来访问非静态成员变量。

方法二:

其实这个方法在GLIB中用的很多,就是放上全局变量地址即

A g_a;

class A
{
public:
static void test()
{
g_a.m_a += ;
}
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 += ;
}
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 += ;
}
void hello()
{
}
private:
static int m_staticA;
int m_a
}; A a;
test(&a);

如上,我整理了4种方法,当然方法还有很多,其实绕了这么大远路,我们的希望就是不破坏回调函数整洁的函数接口(加上自己的实例指针)而做的妥协,如果你更喜欢通过改变接口或者通过用Java类似的interface方式来实现,那也没有问题,这里主要就是提供给大家一个思路,C++确实很灵活,我们要用好这把双刃剑 : )

C++静态成员函数访问非静态成员的几种方法的更多相关文章

  1. C++ 中静态成员函数访问非静态成员变量的方法

    最近在 VS2010 里开发出厂烧写工具,遇到一个问题: 我创建了一个线程,在这个线程里要访问非静态成员,而这个线程函数是静态的.最后找到的办法是用对象指针来做. sourcecode: #test. ...

  2. 关于C++静态成员函数访问非静态成员变量的问题

    静态成员函数不能访问非静态成员,这是因为静态函数属于类而不是属于整个对象,静态函数中的 member可能都没有分配内存.静态成员函数没有隐含的this自变量.所以,它就无法访问自己类的非静态成员 代码 ...

  3. PHP静态成员变量和非静态成员变量

    数据成员可以分静态变量.非静态变量两种. 静态成员: 静态类中的成员加入static修饰符,即是静态成员.可以直接使用类名+静态成员名访问此静态成员,因为静态成员存在于内存,非静态成员需要实例化才会 ...

  4. [C++基础]C++中静态成员函数如何访问非静态成员

    #include <iostream> /* 静态成员函数只能访问静态数据成员.静态成员函数和类以外的函数和数据,不能访问非静态数据成员,但静态成员函数或静态数据成员可由任意访问许可的函数 ...

  5. 为什么c++中,有时可以用类名直接访问非静态成员函数?

    正规的C++语言标准目前(截止到C++14)应该还不支持这种调用方法.目前微软似乎在它的VC++中推行一种叫做C++/CLI的标准,有可能会支持这种调用,如果一定要用这种调用方法的话,还应该用VS20 ...

  6. php取得当前访问url文件名的几种方法

    php下获取当前访问的文件名的几种方法.推荐函数:一是PHP获取当前页面的网址: dedecms用的也是这个哦. <?php //获得当前的脚本网址 function GetCurUrl() { ...

  7. MFC控件编程之 按钮编辑框.静态文本的使用,以及访问控件的七种方法.

    MFC控件编程之 按钮编辑框.静态文本的使用以及访问控件的七种方法. 一丶按钮.静态文本的通用属性. 他们都有一个属性.就是可以输入标题内容.以及可以自定义控件ID. 创建一个MFC Dlg对话框. ...

  8. struts2的action访问servlet API的三种方法

    学IT技术,就是要学习... 今天无聊看看struts2,发现struts2的action访问servlet API的三种方法: 1.Struts2提供的ActionContext类 Object g ...

  9. Action访问Servlet API的三种方法

    一.为什么要访问Servlet API ? Struts2的Action并未与Servlet API进行耦合,这是Struts2 的一个改良,从而方便了单独对Action进行测试.但是对于Web控制器 ...

随机推荐

  1. General: Know How to Use InetAddress

    Modern applications often need the ability to learn information about hosts out on the network. One ...

  2. hdoj 1047 Integer Inquiry

    Integer Inquiry Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)T ...

  3. chromium截图实现

    声明:本blog是我自己写的,假设要转载,请注明:come from blog of niba! chromium终于显示是在ContentView上.但通过硬件加速.渲染合成的网页之前是在surfa ...

  4. SSH服务

    基于Linux的服务器有多个网卡,其中一个网卡连接了网线,通过该网线链接了个人PC.PC上启动Vmware虚拟机,启动ubuntu系统.然后设置PC的网络为自动获取IP,在PC的Linux的Ubunt ...

  5. Android将Activity打成jar包供第三方调用(解决资源文件不能打包的问题)

    转载地址:http://blog.csdn.net/xiaanming/article/details/9257853 最近有一个需要,我们公司做了一个apk客户端,然后其他的公司可以根据自己的需要来 ...

  6. MYSQL 专家 ----zhaiwx_yinfeng

    http://mysqllover.com/?p=708 https://yq.aliyun.com/articles/54454 http://blog.csdn.net/zhaiwx1987/ar ...

  7. bitset使用

    17.10使用序列1.2.3.5.8.13.21初始化一个bitset,将这些位置置位.对另一个bitset进行默认初始化,并编写一小段程序将其恰当的位置位. #include<iostream ...

  8. CentOS 7.2 修改主机名

    1.临时修改主机名 hostname 主机名 重新连接shell,就可以,这种方式,只能修改临时的主机名,当重启机器后,主机名称又变回来了. 2.永久修改主机名 hostnamectl set-hos ...

  9. Ⅲ.AngularJS的点点滴滴-- 路由

    路由ngRoute (需要依赖ngRoute模块) <html> <script src="http://ajax.googleapis.com/ajax/libs/ang ...

  10. ThreadLocal 笔记

    synchronized 同步的机制可以解决多线程并发问题,这种解决方案下,多个线程访问到的都是同一份变量的内容.为了防止在多线程访问的过程中,可能会出现的并发错误.不得不对多个线程的访问进行同步,这 ...