C++中的类成员指针
写在前面:本博客为本人原创,严禁任何形式的转载!本博客只允许放在博客园(.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++中的类成员指针的更多相关文章
- C/C++基础----特殊工具和技术 (重载new和delete,RTT,限定作用域的枚举类型,类成员指针,嵌套类,局部类,volatile,链接指示 extern “C”)
重载new和delete 1调用operator new( 或new[])标准库函数分配足够大的.原始的.未命名的内存空间以便存储特定类型的对象 2编译器运行相应地构造函数以构造这些对象,并为其传入初 ...
- C++ 类成员指针
C++的类成员指针是一种奇葩的指针. 假设现在我们要表示一个三维的点,现在有两种定义方式: struct point1{ int x, y, z; }; struct point2{ int c[3] ...
- C++中static类成员
static局部变量 static局部变量确保不迟于在程序执行流程第一次经过该对象的定义语句时进行初始化 这种对象一旦被创建,在程序结束前不会被撤销.在该函数被多次调用的过程中,静态局部对象会持续存在 ...
- C++ Primer 笔记——类成员指针
1.当我们初始化一个成员指针或为成员指针赋值时,该指针并没有指向任何数据.成员指针指定了成员而非成员所属的对象,只有当解引用成员指针时,我们才提供对象信息. 2.和普通的函数指针类似,如果成员存在重载 ...
- C++类成员指针(指向类成员的指针)
1.指向类的数据成员的指针: 声明格式如下: <类型说明符> <类名>::* <指针变量名>; 2.指向类的成员函数的指针: 声明格式如下: <类型说明符 ...
- [转载] C++ 类中的类成员变量怎么调用带参数的构造函数来初始化?
#include "stdafx.h" class A { public: A(){ax = ;}; A(int a){ax = a;}; int ax; }; class B { ...
- 详解C++中基类与派生类的转换以及虚基类
很详细!转载链接 C++基类与派生类的转换在公用继承.私有继承和保护继承中,只有公用继承能较好地保留基类的特征,它保留了除构造函数和析构函数以外的基类所有成员,基类的公用或保护成员的访问权限在派生类中 ...
- 成员指针与mem_fn
本文是<functional>系列的第4篇. 成员指针是一个非常具有C++特色的功能.更低级的语言(如C)没有类,也就没有成员的概念:更高级的语言(如Java)没有指针,即使有也不会有成员 ...
- C#中增量类功能的方式之 继承与扩展
之前一次公司培训的时候,将它记录下来,https://www.cnblogs.com/AlvinLee/p/10180536.html这个博客上面比较全面. 1.扩展方法 扩展方法是一种特殊的静态方法 ...
随机推荐
- Netty权威指南之Netty入门程序
package com.hjp.netty.netty; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Chan ...
- Maven发布war包到Tomcat
一.修改Tomcat下配置文件tomcat-users.xml,然后启动 <role rolename="manager-gui"/> <role rolenam ...
- Lua协程-测试3
print("Lua 协程测试3") -- 实现消费者-生产者关系(生产一个就消费一个) count = -- 生产总数 -- 生产者 local newProductorCo = ...
- 获取指定ip段的所有存活主机的主机名和操作系统
https://jingyan.baidu.com/article/ceb9fb1089fd948cad2ba000.html java探测局域网存活 https://blog.csdn.net/we ...
- iOS开发-- 如何让 UITableView 的 headerView跟随 cell一起滚动
在我们利用 UITableView 展示我们的内容的时候,我需要在顶部放一个不同于一般的cell的 界面,这个界面比较独特. 1. 所以我就把它 作为一个section的 headerView. 也就 ...
- Nginx 域名重定向
假设 www.old.com 为旧的域名,而 www.new.com 为新的域名,要实现当我们访问 new 的时候自动重定向到 old 域名,配置如下: server { //第一种配置方法 serv ...
- 《C++标准程序库》笔记之三
本篇博客笔记顺序大体按照<C++标准程序库(第1版)>各章节顺序编排. ---------------------------------------------------------- ...
- 使用node新建一个socket服务器连接Telnet客户端并且进行输入的显示
最近在看node的socket,这个很有趣,这个可以很清晰的得到网络http请求的一个过程.首先我们需要一个Telnet的客户端,node(博主为8.0+版本) Telnet客户端的开启过程 有的系统 ...
- session超时跃出iframe并跳到登陆页面(转载)
session超时跳出iframe并跳到登陆页面 在网页编程时,我们经常需要处理,当session过期时,我们要跳到登陆页面让用户登陆,由于我们可能用到IFrame框架,所以我们我登陆页面需要显示在整 ...
- Linux记录用户shell命令
在/etc/profile中添加下面内容: export LC_ALL=C TMOUT=3600 HISTFILESIZE=2000 HISTSIZE=2000 HISTTIMEFORMAT=&quo ...