写在前面:本博客为本人原创,严禁任何形式的转载!本博客只允许放在博客园(.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. iptables相关操作以及简单理解端口和服务之间关系

    一般CentOS7默认安装的是firewall不是iptables 1.查看firewall状态 firewall-cmd --state 关闭后显示not running,开启后显示running ...

  2. springJdbc in 查询,Spring namedParameterJdbcTemplate in查询

    springJdbc in 查询,Spring namedParameterJdbcTemplate in查询, SpringJdbc命名参数in查询,namedParameterJdbcTempla ...

  3. 个人成长|荣获CNVD年度最有价值漏洞奖

    本文共750+字,预计阅读2-3分钟. 前几天,很荣幸受主办方邀请,还拿了CNVD的一个“年度最有价值漏洞奖”,说一说,这几天的故事吧. 11月20号,意外收到一个会议邀请,当时还比较诧异,印象中我在 ...

  4. [PyCharm] 设置自动启动时自动打开项目

    设置启动PyCharm时自动打开(或不打开)上次进行的项目: 选择 “Settings - General - Reopen last project on startup”,勾选该选项则启动时自动打 ...

  5. [Z]修炼成C++高手必看的C++书单

    增添于网上的一些书单: C++/OPP/OOD系列: 层级一:语法/语意(C++) [Lippman2000] Essential C++ Essential C++,by Stanley B. Li ...

  6. hadoop自动提交脚本

    自动提交到hadoop系统,然后调用wordcount的任务,并下载输出的文件. #!/bin/sh #从给定的路径获取文件列表,提交到hadoop系统,使用wordcount的功能统计单词数量 #e ...

  7. WP8.1学习系列(第二十四章)——Json解析

    .net已经集成了json解析,类名叫DataContractJsonSerializer DataContractJsonSerializer 类型公开以下成员. 构造函数     名称 说明 Da ...

  8. python框架---->APScheduler的使用

    这里介绍一下python中关于定时器的一些使用,包括原生的sche包和第三方框架APScheduler的实现.流年未亡,夏日已尽.种花的人变成了看花的人,看花的人变成了葬花的人. python中的sc ...

  9. 第二步 (仅供参考) sencha touch 使用cmd打包apk

    最新版本的cmd可以直接将sencha touch项目打包成本地应用,不过还有很多不足,本文仅供参考 通过sencha app build native命令可以直接将项目打包成本地应用,不过在命令运行 ...

  10. 一个lucene源码分析的博客

    ITpub上的一个lucene源码分析的博客,写的比较全面:http://blog.itpub.net/28624388/cid-93356-list-1/