写在前面:本博客为本人原创,严禁任何形式的转载!本博客只允许放在博客园(.cnblogs.com),如果您在其他网站看到这篇博文,请通过下面这个唯一的合法链接转到原文!

本博客全网唯一合法URL:http://www.cnblogs.com/acm-icpcer/p/6729273.html

C++中的类成员指针

  在上一篇文章中我提到了C++中的函数指针。那么如果想定义一个指向类数据成员或者函数成员的指针,又该怎么办呢?

  本质上讲和之前我提到的写法没有什么不同,只不过是要加上域定义而已。

1.类数据成员指针

  例如,对于下面的类A:

class A
{
public:
int x;
int sayhello()
{
cout<<"hello world"<<endl;
}
};

  假如我想定义一个指向数据成员x的指针,则:

  int A::*pointer1 = &A::x;

  很明显,去掉域定义其实就是普通的指针定义:int pointer1=&x;

  那么,如果用typedef来简化语法就是:

  typedef int A::*int_pointer;

  int_pointer pointer2 = &A::x;

  两者是等价的。

  调用指针时则为:

    A a;
a.*pointer1 = ;
++(a.*pointer2);
cout << &a->*pointer1 << endl;

  结果为7。(注意:必须声明一个A的对象才可以调用类数据成员指针)

  那么这个类数据成员指针究竟是地址还是什么呢?

  为了搞清楚,我们就把它打出来看看吧:

  cout << pointer1 << endl << pointer2 << endl;

  结果是1    1。

  这是什么意思呢?实际上,类数据成员指针只是相对于对象在内存中初始地址的一个偏移量,也就是说,它是一个相对地址。

2.类函数成员指针

  现在,我们讨论一下类函数成员指针的定义和使用。我们的讨论建立在以下类A和类B的基础上来讲:

class A
{
private:
int y;
public:
double w;
int x;
int sayhello()
{
cout<<"hello world"<<endl;
}
}; class B:public A
{ };

  类成员函数指针定义:

  int (A::*classAfunctionpointer1)();

  classAfunctionpointer1 = &A::sayhello;

  可以看到,这其实也是在普通的全局函数指针前面加上了一个域定义而已(普通全局函数指针:int (*classAfunctionpointer1)();)。

  那么,如果用typedef来简化语法就是:

  typedef int (A::*FP)();

  FP classAfunctionpointer2 = &A::sayhello;

  调用时都是一样的:

  (a.*classAfunctionpointer1)();

  (a.*classAfunctionpointer2)();

  或者

  (&a->*classAfunctionpointer1)();

  (&a->*classAfunctionpointer2)();

  结果都是打印出hello world。(注意:类成员函数指针在使用前必须先声明一个对象)

  那么,类B继承了类A,理论上讲B也可以使用A的指针:

  B b;

  (b.*classAfunctionpointer1)();

  确实可以,结果也是打印出hello world。

  那么这又是为什么呢?

  实际上,类成员函数的地址是绝对的,因为类成员函数是定义在一个固定的代码区中。当年使用不同的对象去调用同一个类成员函数的时候,本质上,编译器会把该对象的this指针默认加在该成员函数的形参列表中,以便让函数明白是谁在调用它。所以不同的对象去调用同一个类成员函数的时候,编译器才能理解并作出反应。

  

3.示例代码

  好了,根据上面讲到的所有基础知识,我给出如下程序:

#include<iostream>
using namespace std; class A
{
private:
int y;
public:
double w;
int x;
int sayhello()
{
cout<<"hello world"<<endl;
}
}; class B:public A
{ }; typedef int A::*int_pointer;
typedef int (A::*FP)(); int main()
{
int A::*pointer1 = &A::x;
int_pointer pointer2 = &A::x;
A a;
a.*pointer1 = ;
++(a.*pointer2);
cout << &a->*pointer1 << endl << pointer1 << endl << pointer2 << endl; double A::*pointer3 = &A::w;
cout<<pointer3<<endl; B b;
a.sayhello();
int (A::*classAfunctionpointer1)();
classAfunctionpointer1 = &A::sayhello;
FP classAfunctionpointer2 = &A::sayhello;
(a.*classAfunctionpointer1)();
(a.*classAfunctionpointer2)();
(&a->*classAfunctionpointer1)();
(b.*classAfunctionpointer1)(); return ;
}

TZ

2017/4/18于华中农业大学

C++中的类成员指针的更多相关文章

  1. C/C++基础----特殊工具和技术 (重载new和delete,RTT,限定作用域的枚举类型,类成员指针,嵌套类,局部类,volatile,链接指示 extern “C”)

    重载new和delete 1调用operator new( 或new[])标准库函数分配足够大的.原始的.未命名的内存空间以便存储特定类型的对象 2编译器运行相应地构造函数以构造这些对象,并为其传入初 ...

  2. C++ 类成员指针

    C++的类成员指针是一种奇葩的指针. 假设现在我们要表示一个三维的点,现在有两种定义方式: struct point1{ int x, y, z; }; struct point2{ int c[3] ...

  3. C++中static类成员

    static局部变量 static局部变量确保不迟于在程序执行流程第一次经过该对象的定义语句时进行初始化 这种对象一旦被创建,在程序结束前不会被撤销.在该函数被多次调用的过程中,静态局部对象会持续存在 ...

  4. C++ Primer 笔记——类成员指针

    1.当我们初始化一个成员指针或为成员指针赋值时,该指针并没有指向任何数据.成员指针指定了成员而非成员所属的对象,只有当解引用成员指针时,我们才提供对象信息. 2.和普通的函数指针类似,如果成员存在重载 ...

  5. C++类成员指针(指向类成员的指针)

    1.指向类的数据成员的指针: 声明格式如下: <类型说明符> <类名>::* <指针变量名>; 2.指向类的成员函数的指针: 声明格式如下:   <类型说明符 ...

  6. [转载] C++ 类中的类成员变量怎么调用带参数的构造函数来初始化?

    #include "stdafx.h" class A { public: A(){ax = ;}; A(int a){ax = a;}; int ax; }; class B { ...

  7. 详解C++中基类与派生类的转换以及虚基类

    很详细!转载链接 C++基类与派生类的转换在公用继承.私有继承和保护继承中,只有公用继承能较好地保留基类的特征,它保留了除构造函数和析构函数以外的基类所有成员,基类的公用或保护成员的访问权限在派生类中 ...

  8. 成员指针与mem_fn

    本文是<functional>系列的第4篇. 成员指针是一个非常具有C++特色的功能.更低级的语言(如C)没有类,也就没有成员的概念:更高级的语言(如Java)没有指针,即使有也不会有成员 ...

  9. C#中增量类功能的方式之 继承与扩展

    之前一次公司培训的时候,将它记录下来,https://www.cnblogs.com/AlvinLee/p/10180536.html这个博客上面比较全面. 1.扩展方法 扩展方法是一种特殊的静态方法 ...

随机推荐

  1. VS2013 编译&使用 stlport

    1. 下载stlport.   下载地址:http://sourceforge.net/projects/stlport/ 2. 解压到一个目录下面, 我的是解压到D:\project_kuku\pr ...

  2. PyCharm使用Github管理代码

    本篇文章主要写一下如何通过pycharm客户端来上传下载代码. 安装Git 在Windows上使用Git,可以从Git官网直接下载安装程序,(网速慢的同学请移步国内镜像),然后按默认选项安装即可. 安 ...

  3. 【Android】录音-amr音频录制

    http://www.cnblogs.com/fengzhblog/archive/2013/08/01/3231500.html http://blog.csdn.net/fan7983377/ar ...

  4. RESTFul basic introduction

    http://www.ruanyifeng.com/blog/2011/09/restful.html

  5. wordpress for sae

    帮人建个站,准备用sae+wordpess,小研究一下 http://sae.sina.com.cn/?m=apps&a=detail&aid=1 http://wp4sae.org/ ...

  6. Kafka 0.11客户端集群管理工具AdminClient

    很多用户都有直接使用程序API操作Kafka集群的需求.在0.11版本之前,kafka的服务器端代码(即添加kafka_2.**依赖)提供了AdminClient和AdminUtils可以提供部分的集 ...

  7. XML的基本用法

    一.概述 XML全称为可扩展的标记语言.主要用于描述数据和用作配置文件. XML文档在逻辑上主要由一下5个部分组成: XML声明:指明所用XML的版本.文档的编码.文档的独立性信息 文档类型声明:指出 ...

  8. 【EF框架】使用params参数传值防止SQL注入报错处理

    通过SqlParameter传时间参数,代码如下: var param = new List<SqlParameter>(); param.Add(new SqlParameter(&qu ...

  9. try except与try finally不同之处

    try except与try finally不同之处 try//尝试执行 {SomeCode}  except//出错的时候执行, Except有特定的错误类型  {SomeCode}  end; t ...

  10. Win 7打开任务管理器的几种方法

    1. 按住Ctrl和Alt键和Delete键 2. 快速启动栏打开win7任务管理器 3. Ctrl键+Shift键+Esc键的组合键 4. 桌面新建一个文本文档也叫记事本,打开,输入“C:\Wind ...