深度探索C++对象模型这本书还有提到C++类的成员变量指针和成员函数指针,虽然在实际开发中用的不多,但是还是需要理解下。

一:成员变量指针

1.1 非静态成员指针

类成员变量指针,实际上并不是真正意义上的指针,即它并不是指向内存中某个地址,而是该成员变量与对象指针的偏移量。该偏移量只有附着在某个具体对象,才能指向对象成员变量的具体地址。

如下程序:

#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
class A
{
public:A(int a=0,int b=0):a(a),b(b){}void print(){cout<<"a="<<a<<"  "<<"b="<<b<<endl;}
public:int a;int b;
};
typedef void (A::*pFun)(void);
int main(void)
{A ap;ap.print();//输出a和b的默认值int A::*aptr=&A::a;//aptr为A这个类中,a的成员指针int A::*bptr=&A::b;aptr为A这个类中,a的成员指针printf("aptr=%d,bptr=%d\n",aptr,bptr);//输出两个指针值ap.*bptr=5;通过成员指针修改成员的值ap.print();return 0;
}

该程序的输出如下:

a=0 b=0
aptr=0,bptr=4
a=0 b=5

由结果可以看出,指向a的指针值为0,指向b的指针值为4,刚好都是这两个变量在类A实例对象中,与对象指针的偏移量。然后通过将该指针绑定到一个对象,修改该对象的值,也是可以成功的。因为平时,我们用ap.a访问变量a时,编译器就是将ap+a的偏移量来访问的。

1.2 静态成员

对于C++静态成员的指针,其值就是指向内存中数据区某个地址,就是真正意义上的指针,因为静态成员属于类范围,不属于某个对象。

编写如下程序验证:

#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
class A
{
public:A(){}void print(){cout<<"a="<<a<<endl;}
public:static int a;
};
int A::a=1;
typedef void (A::*pFun)(void);
int main(void)
{const int *p=&A::a;printf("p=%p\n",p);return 0;
}

该程序输出如下:

p=0x601058

说明下:C++类的静态成员必须在类外初始化,而且初始化一次。如果是const static int a即可在类里面初始化。

二:成员函数指针

 2.1 非静态函数指针

C++非静态成员函数的指针,其值就是指向一块内存地址。但是指针不能直接调用,它需要绑定到一个对象才能调用。 例子程序如下:

#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
class A
{
public:A(int i=3):a(i){}void test(){cout<<"a="<<a<<endl;}
public:int a;
};
typedef void (A::*pFun)(void);
int main(void)
{A ap;pFun fun=&A::test;printf("%p\n",&A::test);//fun();(ap.*fun)();return 0;
}

该程序的输出如下:

0x4009d8
a=3

由输出可以看出的确是一个真正意义上的地址指针。但是为什么一定要绑定一个对象了?我的猜想是因为该函数可能会修改成员变量,而修改成员变量必须传入对象指针,所以必须与对象绑定在一起。

2.2 虚拟成员函数指针

虚拟成员函数指针的值表示该函数在虚函数表中,离表头的偏移量+1。因为在通过反汇编代码知道当一个对象调用虚拟函数时,主要是通过

  1. 获取指向虚函数表指针的值。
  2. 指向虚函数表指针的值加上虚函数离表头的偏移量即为该函数的地址。
    所以虚函数表示虚函数在虚函数表的偏移量+1,在、再绑定到一个对象,即可调用这个虚函数。

实例程序如下:

#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
class A
{
public:A(int i=3):a(i){}virtual void test1(){cout<<"a="<<a<<endl;}virtual void test2(){cout<<"a="<<a<<endl;}virtual void test3(){cout<<"a="<<a<<endl;}
public:int a;
};
typedef void (A::*pFun)(void);
int main(void)
{A ap;pFun fun=&A::test3;printf("%p\n",&A::test1);printf("%p\n",&A::test2);printf("%p\n",&A::test3);(ap.*fun)();return 0;
}

该程序输出如下:

0x1
0x9
0x11//十进制数为17
a=3

因为我这是在64位系统下跑的,所以指针大小为8字节,三个虚函数,所以输出三个地址,他们之间相差8个字节,即指针的大小.

2.3 静态函数

静态函数的指针的值,和静态成员指针的值一样,也是真正意义上的指针,指向内存中某个地址。

实例程序如下:

#include <cstdio>
#include <cstdlib>
#include <iostream>
using namespace std;
class A
{
public:A(){}static void test(){cout<<"a="<<a<<endl;}
public:static int a;
};
int A::a=1;
typedef void (*pFun)(void);
int main(void)
{A ap;pFun fun=&A::test;printf("%p\n",&A::test);fun();//opt不需要绑定到一个对象return 0;
}

该程序输出如下:

0x400986
a=1

谈谈我对这些指针本质上的理解。

一个类,当它编译,运行,实例化一个对象时,在内存中总是可以找到该对象的所有成员变量和函数地址。

非静态成员通过对象指针+偏移量访问。
虚函数可以通过对象指针加偏移量得到。
静态成员,非静态函数,静态函数可以通过链接时获得。

所以:

非静态成员指针表示一个偏移量,因为通过对象可以访问到。
虚函数指针表示虚函数地址在虚函数表中的偏移量。
静态成员,非静态函数和静态函数不能通过对象指针直接访问到,所以这三个的指针类型必须是具体的函数地址。

转载自:http://luodw.cc/2015/10/10/ptr/

C++成员变量指针和成员函数指针相关推荐

  1. 类的成员函数指针和静态成员函数指针 调用成员函数***

    C++提供static这个关键词对静态成员进行声明,静态成员函数和类的实例化无关,对于同一类来说,静态成员函数是所有类的对象共享的.而普通成员函数需要实例化才能调用,对于每一个实例来说,普通成员函数是 ...

  2. 【C 语言】指针 与 数组 ( 指针 | 数组 | 指针运算 | 数组访问方式 | 字符串 | 指针数组 | 数组指针 | 多维数组 | 多维指针 | 数组参数 | 函数指针 | 复杂指针解读)

    相关文章链接 : 1.[嵌入式开发]C语言 指针数组 多维数组 2.[嵌入式开发]C语言 命令行参数 函数指针 gdb调试 3.[嵌入式开发]C语言 结构体相关 的 函数 指针 数组 4.[嵌入式开发 ...

  3. 数组指针和指针数组,函数指针和指针函数,常量指针和指针常量,常量引用

    一.数组指针和指针数组 1.数组指针(行指针) 首先要知道数组指针是指向数组的指针.所以数组指针本质是个指针,只不过指向一个数组而已.格式为:T (*ptr)[]. 注意:"[]" ...

  4. C语言程序设计 | 指针(二):常量指针和指针常量、数组参数和指针参数、函数指针数组

    指针的进阶(二)目录: 常量指针和指针常量 数组参数和指针参数 函数指针数组 常量指针和指针常量 在我们日常中,经常会用到一个关键字const const是一个C语言(ANSI C)的关键字,具有着举 ...

  5. delphi7存储过程传入数组_C++中的指针、数组指针与指针数组、函数指针与指针函数...

    本文从初学者的角度,深入浅出地详解什么是指针.如何使用指针.如何定义指针.如何定义数组指针和函数指针,并给出对应的实例演示:接着,区别了数组指针与指针数组.函数指针与指针函数:最后,对最常混淆的引用传 ...

  6. [转] 彻底了解指针数组,数组指针,以及函数指针,以及堆中的分配规则

    一 :关于指针和堆的内存分配 先来介绍一下指针: 指针一种类型,理论上来说它包含其他变量的地址,因此有的书上也叫它:地址变量.既然指针是一个类型,是类型就有大小,在达内的服务器上或者普通的PC机上,都 ...

  7. 【C语言】指针进阶 - 指针数组 数组指针 数组指针传参 函数指针 指向函数指针数组的指针

    目录 一.字符指针 一道题 二. 指针数组 解引用打印数组元素 &数组名 数组名 字符指针初始化 三.数组指针 取数组地址-放在数组指针里 类型 数组指针的使用 二维数组传参 判断 四.数组参 ...

  8. 函数指针 和 函数指针数组 和 函数指针数组

    //先看一些函数指针的例子(吸纳了网上兄弟的方法) #include <stdio.h> void MyFun(int x); //这个申明也可写成:void MyFun( int ); ...

  9. 指针难点——数组指针、指针数组、函数指针、指针函数详解

    指针难点 1.指针 1.1指针数组和数组指针 2.右左法则 3.函数指针和指针函数 示例1 示例2 示例3(面试题) 1.指针 1.1指针数组和数组指针 指针数组是一个数组,数组里面存放的内容是指针 ...

  10. 【C++学习】指针数组,数组指针,以及函数指针,以及堆中的分配规则--有是一篇好文章,收到自己门下 慢慢学习

    一 :关于指针和堆的内存分配 先来介绍一下指针 : 指针一种类型,理论上来说它包含其他变量的地址,因此有的书上也叫它:地址变量.既然指针是一个类型,是类型就有大小,在达内的服务器上或者普通的PC机上, ...

最新文章

  1. 在sublime中让html和css链接
  2. DS4700电池更换步骤
  3. java 反射内部匿名内部类_android-反射的使用(反射静态内部类、非静态内部类、匿名内部类等)...
  4. bzoj1233 单调队列优化dp
  5. python3.6安装pyspider
  6. c int转字符串_零基础如何学好Python 之int 数字整型类型 定义int()范围大小转换...
  7. 火山安卓简单分组列表框
  8. java函数式编程的好处
  9. 视频教程-oracle入门到大神(备mysql、java基础、javaee必经之路)-Oracle
  10. apple music导入本地歌曲及歌词
  11. 简洁Python命名规范
  12. 保研面试中常见的英语问题有哪些?
  13. mapinfo mif/mid文件格式详解
  14. Keychron Q1:客制化机械键盘|体验
  15. Zookeeper:实现节点Barriers(即限定操作)
  16. 【树莓派C语言开发】实验03:七彩LED模块
  17. Day55-每日一道Java面试题-Java 面向对象编程三大特性: 封装 继承 多态
  18. 环保数据采集仪_环保采集仪_环保数据采集器
  19. 获取单支股票历史交易数据和当前数据的免费接口 API
  20. 跨专业考研必须要了解的5个常识!

热门文章

  1. 虚拟地址,虚拟地址空间, 交换分区
  2. D. Rescue Nibel(cf) 区间覆盖 + 组合数学
  3. 你真的了解AsyncTask吗?AsyncTask源码分析
  4. 在vc中使用xtremetoolkit界面库-----安装及环境配置
  5. oracle日期函数大全一(Date)
  6. position:sticky 粘性定位 (sticky) 与 固定定位
  7. 基于SpringBoot的毕业论文管理系统的设计与实现(开题报告)
  8. Matlab bsxfun函数
  9. MVC设计模式 吉软
  10. python实现mysql二叉树_python环境下使用mysql数据及数据结构和二叉树算法(图)...