写在前面:本博客为本人原创,严禁任何形式的转载!本博客只允许放在博客园(.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. backbone学习笔记:视图(View)

    Backbone 视图对象主要用来渲染数据,监听事件. Backbone的视图对象可以展示Model数据,也可以把用户编辑的Model数据传递到后台,可以通过监听事件操作视图里的DOM元素 举例: v ...

  2. setcursor 与 showcursor

    Windows为鼠标光标保存了一个「显示计数」.如果安装了鼠标,显示计数会被初始化为0:否则,显示计数会被初始化为-1. 只有在显示计数非负时才显示鼠标光标.要增加显示计数,呼叫:ShowCursor ...

  3. Swift - 可选类型详解

    可选类型详解 直接上代码解释 // 类中所有的属性在对象初始化时,必须有初始化值 class Person : NSObject { var name : String? var view : UIV ...

  4. Android学习之蓝牙操作

    BluetoothAdapter 用法 蓝牙运行原理:通过BluetoothAdapter 蓝牙适配器处理任务,如果蓝牙被启动之后,系统会自动去搜索其它设备,如果匹配到附近的设备就发送一个广播,Bro ...

  5. Android学习之DatePicker和TimePicker

    在Android开发的应用程序中,通常都会有时间和日期选择的需求,下面就对日期选择控件DatePicker和时间选择控件TimePicker的基本使用方法进行介绍:        DatePicker ...

  6. cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration的解决

    导入了一个工程,编译什么的都还好,但是报了一个XML的错误. cvc-complex-type.2.4.c: The matching wildcard is strict, but no decla ...

  7. uefi安装win7,deepin15双系统后grub没有windows选项

    本帖最后由 873792861 于 2015-12-23 16:17 编辑 如题,首先电脑是GPT+uefi的,电脑上安装有64位的win7.用U盘工具制造好驱动U盘后,在安装时选择 专家模式 ,选择 ...

  8. luanet分布式lua框架

    luanet最初只是一个网络框架,它简单的封装了一些网络相关接口然后暴露到lua中,让lua可以构建简单的网络应用. 随着我的手游服务器的开发,我发现在C语言中要实现一个简洁易用的RPC调用接口并不容 ...

  9. Objective-c官方文档 怎么使用对象

    版权声明:原创作品,谢绝转载!否则将追究法律责任.   对象发送和接受消息 尽管有不同的方法来发送消息在对象之间,到目前位置是想中括号那样[obj doSomeThing]:左边是接受消息的接收器,右 ...

  10. 【linux系列】centos安装vsftp

    一.检查vsftpd软件 如果发现上不了网可以修改配置文件中的ONBOOT=no改为yes,然后重启服务试试