C++指向类成员的函数指针

2023-10-26

指向类成员函数的函数指针

定义:类成员函数指针(member function pointer),是 C++ 语言的一类指针数据类型,用于存储一个指定类具有给定的形参列表与返回值类型的成员函数的访问信息。

基本上要注意的有两点:

1、函数指针赋值要使用 &
2、使用 .* (实例对象)或者 ->*(实例对象指针)调用类成员函数指针所指向的函数
下面看两个例子:

A) 类成员函数指针指向类中的非静态成员函数

对于 nonstatic member function (非静态成员函数)取地址,获得该函数在内存中的实际地址

对于 virtual function(虚函数), 其地址在编译时期是未知的,所以对于 virtual member function(虚成员函数)取其地址,所能获得的只是一个索引值

//指向类成员函数的函数指针
#include <iostream>
#include <cstdio>
using namespace std;
 
class A
{
    public:
        A(int aa = 0):a(aa){}
 
        ~A(){}
 
        void setA(int aa = 1)
        {
            a = aa;
        }
        
        virtual void print()
        {
            cout << "A: " << a << endl;
        }
 
        virtual void printa()
        {
            cout << "A1: " << a << endl;
        }
    private:
        int a;
};
 
class B:public A
{
    public:
        B():A(), b(0){}
        
        B(int aa, int bb):A(aa), b(bb){}
 
        ~B(){}
 
        virtual void print()
        {
            A::print();
            cout << "B: " << b << endl;
        }
 
        virtual void printa()
        {
            A::printa();
            cout << "B: " << b << endl;
        }
    private:
        int b;
};
 
int main(void)
{
    A a;
    B b;
    void (A::*ptr)(int) = &A::setA;
    A* pa = &a;
    
    //对于非虚函数,返回其在内存的真实地址
    printf("A::set(): %p\n", &A::setA);
    //对于虚函数, 返回其在虚函数表的偏移位置
    printf("B::print(): %p\n", &A::print);
    printf("B::print(): %p\n", &A::printa);
 
    a.print();
 
    a.setA(10);
 
    a.print();
 
    a.setA(100);
 
    a.print();
    //对于指向类成员函数的函数指针,引用时必须传入一个类对象的this指针,所以必须由类实体调用
    (pa->*ptr)(1000);
 
    a.print();
 
    (a.*ptr)(10000);
 
    a.print();
    return 0;
}

执行以上代码,输出结果为:

A::set(): 0x8048a38
B::print(): 0x1
B::print(): 0x5
A: 0
A: 10
A: 100
A: 1000
A: 10000

B) 类成员函数指针指向类中的静态成员函数

#include <iostream>
using namespace std;
 
class A{
public:
    
    //p1是一个指向非static成员函数的函数指针
    void (A::*p1)(void);
    
    //p2是一个指向static成员函数的函数指针
    void (*p2)(void);
    
    A(){
        /*对
         **指向非static成员函数的指针
         **和
         **指向static成员函数的指针
         **的变量的赋值方式是一样的,都是&ClassName::memberVariable形式
         **区别在于:
         **对p1只能用非static成员函数赋值
         **对p2只能用static成员函数赋值
         **
         **再有,赋值时如果直接&memberVariable,则在VS中报"编译器错误 C2276"
         **参见:http://msdn.microsoft.com/zh-cn/library/850cstw1.aspx
         */
        p1 =&A::funa; //函数指针赋值一定要使用 &
        p2 =&A::funb;
        
        //p1 =&A::funb;//error
        //p2 =&A::funa;//error
        
        //p1=&funa;//error,编译器错误 C2276
        //p2=&funb;//error,编译器错误 C2276
    }
    
    void funa(void){
        puts("A");
    }
    
    static void funb(void){
        puts("B");
    }
};
 
int main()
{
    A a;
    //p是指向A中非static成员函数的函数指针
    void (A::*p)(void);
    
    (a.*a.p1)(); //打印 A
    
    //使用.*(实例对象)或者->*(实例对象指针)调用类成员函数指针所指向的函数
    p = a.p1;
    (a.*p)();//打印 A
    
    A *b = &a;
    (b->*p)(); //打印 A
    
    /*尽管a.p2本身是个非static变量,但是a.p2是指向static函数的函数指针,
     **所以下面这就话是错的!
     */
//    p = a.p2;//error
    
    void (*pp)(void);
    pp = &A::funb;
    pp(); //打印 B
    
    return 0;
}

总结

类成员函数指针与普通函数指针不是一码事。前者要用 .* 与 ->* 运算符来使用,而后者可以用 * 运算符(称为"解引用"dereference,或称"间址"indirection)。普通函数指针实际上保存的是函数体的开始地址,因此也称"代码指针",以区别于 C/C++ 最常用的数据指针。而类成员函数指针就不仅仅是类成员函数的内存起始地址,还需要能解决因为 C++ 的多重继承、虚继承而带来的类实例地址的调整问题,所以类成员函数指针在调用的时候一定要传入类实例对象。

原文连接

https://www.runoob.com/w3cnote/cpp-func-pointer.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++指向类成员的函数指针 的相关文章

  • Signalr 在生产服务器中总是陷入长轮询

    当我在服务器中托管应用程序时 它会检查服务器端事件并始终回退到长轮询 服务器托管环境为Windows Server 2012 R1和IIS 7 5 无论如何 我们是否可以解决这个问题 https cloud githubuserconten
  • 如何在没有 Control.Invoke() 的情况下从后台线程修改控件属性

    最近 我们遇到了一些旧版 WinForms 应用程序 我们需要更新一些新功能 在专家测试该应用程序时 发现一些旧功能被破坏 无效的跨线程操作 现在 在您认为我是新手之前 我确实有一些 Windows 窗体应用程序的经验 我不是专家 但我认为
  • 嵌入式系统中的malloc [重复]

    这个问题在这里已经有答案了 我正在使用嵌入式系统 该应用程序在 AT91SAMxxxx 和 cortex m3 lpc17xxx 上运行 我正在研究动态内存分配 因为它会极大地改变应用程序的外观 并给我更多的力量 我认为我唯一真正的路线是为
  • Cygwin 下使用 CMake 编译库

    我一直在尝试使用 CMake 来编译 TinyXML 作为一种迷你项目 尝试学习 CMake 作为补充 我试图将其编译成动态库并自行安装 以便它可以工作 到目前为止 我已经设法编译和安装它 但它编译成 dll 和 dll a 让它工作的唯一
  • C# 中可空类型是什么?

    当我们必须使用nullable输入 C net 任何人都可以举例说明 可空类型 何时使用可空类型 https web archive org web http broadcast oreilly com 2010 11 understand
  • 将字符串从非托管代码传递到托管

    我在将字符串从非托管代码传递到托管代码时遇到问题 在我的非托管类中 非托管类 cpp 我有一个来自托管代码的函数指针 TESTCALLBACK FUNCTION testCbFunc TESTCALLBACK FUNCTION 接受一个字符
  • 使用 C# 在 WinRT 中获取可用磁盘空间

    DllImport kernel32 dll SetLastError true static extern bool GetDiskFreeSpaceEx string lpDirectoryName out ulong lpFreeBy
  • 使用 Google Analytics API 在 C# 中显示信息

    我一整天都在寻找一个好的解决方案 但谷歌发展得太快了 我找不到有效的解决方案 我想做的是 我有一个 Web 应用程序 它有一个管理部分 用户需要登录才能查看信息 在本节中 我想显示来自 GA 的一些数据 例如某些特定网址的综合浏览量 因为我
  • C# 用数组封送结构体

    假设我有一个类似于 public struct MyStruct public float a 我想用一些自定义数组大小实例化一个这样的结构 在本例中假设为 2 然后我将其封送到字节数组中 MyStruct s new MyStruct s
  • 按字典顺序对整数数组进行排序 C++

    我想按字典顺序对一个大整数数组 例如 100 万个元素 进行排序 Example input 100 21 22 99 1 927 sorted 1 100 21 22 927 99 我用最简单的方法做到了 将所有数字转换为字符串 非常昂贵
  • Windows 窗体不会在调试模式下显示

    我最近升级到 VS 2012 我有一组在 VS 2010 中编码的 UI 测试 我试图在 VS 2012 中启动它们 我有一个 Windows 窗体 在开始时显示使用 AssemblyInitialize 属性运行测试 我使用此表单允许用户
  • 线程、进程和 Application.Exit()

    我的应用程序由主消息循环 GUI 和线程 Task Factory 组成 在线程中我调用一些第三方应用程序var p new Process 但是当我调用Application Exit 在消息循环中 我可以看到在线程中启动的进程仍在内存中
  • C 中的位移位

    如果与有符号整数对应的位模式右移 则 1 vacant bit will be filled by the sign bit 2 vacant bit will be filled by 0 3 The outcome is impleme
  • 在 URL 中发送之前对特殊字符进行百分比编码

    我需要传递特殊字符 如 等 Facebook Twitter 和此类社交网站的 URL 为此 我将这些字符替换为 URL 转义码 return valToEncode Replace 21 Replace 23 Replace 24 Rep
  • 作为字符串的动态属性名称

    使用 DocumentDB 创建新文档时 我想设置属性名称动态地 目前我设置SomeProperty 像这样 await client CreateDocumentAsync dbs db colls x new SomeProperty
  • char指针或char变量的默认值是什么[重复]

    这个问题在这里已经有答案了 下面是我尝试打印 char 变量和指针的默认值 值的代码 但无法在控制台上看到它 它是否有默认值或只是无法读取 ASCII 范围 include
  • 窗体最大化时自动缩放子控件

    有没有办法在最大化屏幕或更改分辨率时使 Windows 窗体上的所有内容自动缩放 我发现手动缩放它是正确的 但是当切换分辨率时我每次都必须更改它 this AutoScaleDimensions new System Drawing Siz
  • 如何使用 ReactiveList 以便在添加新项目时更新 UI

    我正在创建一个带有列表的 Xamarin Forms 应用程序 itemSource 是一个reactiveList 但是 向列表添加新项目不会更新 UI 这样做的正确方法是什么 列表定义 listView new ListView var
  • 如何在 C# 中播放在线资源中的 .mp3 文件?

    我的问题与此非常相似question https stackoverflow com questions 7556672 mp3 play from stream on c sharp 我有音乐网址 网址如http site com aud
  • 将变量分配给另一个变量,并将一个变量的更改反映到另一个变量中

    是否可以将一个变量分配给另一个变量 并且当您更改第二个变量时 更改会瀑布式下降到第一个变量 像这样 int a 0 int b a b 1 现在 b 和 a 都 1 我问这个问题的原因是因为我有 4 个要跟踪的对象 并且我使用名为 curr

随机推荐

  • rancher部署flink集群

    rancher版本 v2 6 8 k8s版本 v1 22 13 rke2r1 flink集群版本 1 15 0 flink安装模式 session cluster 写在前面 因为参照官网的说明安装过程中出现了很多问题 特记录于此 避免后续重
  • 2020-6-19 Idea打包项目war并且发布到服务器

    打包的介绍 打包和上传到服务器的介绍
  • linux操作系统发行版_Linux操作系统和发行版

    linux操作系统发行版 Newcomers to Linux world generally confuse or no idea about distributions We call generally the operating s
  • ChatGPT能代替搜索引擎吗?ChatGPT和搜索引擎有什么区别?

    ChatGPT和搜索引擎是两种在信息获取和交流中常用的工具 ChatGPT是一种基于人工智能技术的聊天机器人 而搜索引擎是一种在互联网上搜索信息的工具 尽管它们都是依托互联网与信息获取和交流有关 部分功能重合 但在很多方面存在着明显的区别
  • JS逆向

    关注它 不迷路 本文章中所有内容仅供学习交流 不可用于任何商业用途和非法用途 否则后果自负 如有侵权 请联系作者立即删除 1 需求 最近美食群发了很多二维码 提取链接后 可以在移动端的浏览器上愉快的播放 然而 当我把 url 链接复制到 我
  • mac安装vue

    需要提前安装brew 安装方法 mac使用Homebrew安装node 1 安装node 上面链接已经详细介绍如何安装node 这里一笔带过 brew install nodejs node v 2 安装webpack cnpm insta
  • 令人眼花缭乱的区块链名词之:UTXO

    目录 1 交易 2 UTXO hello 大家好 我们第六期的区块链技术分享来啦 本期分享的主题是UTXO Unspent Transaction output 未花费的交易输出 在比特币系统中 每个全节点都会记录UTXO 要理解UTXO模
  • python 爬取今日头条热点新闻

    嗯 今天就让我们来一起爬爬今日头条的热点新闻吧 今日头条地址 https www toutiao com ch news hot 在浏览器中打开今日头条的链接 选中左侧的热点 在浏览器开发者模式 network下很快能找到一个 catego
  • Qt应用程序自动重启(零零散散)

    老有人问如何让Qt的应用程序自动重启 稍微写一点 也顺便理理自己的思路 2011 10 26 自动重启 也就是退出当前进程 启动一个新的进程 于是 先看程序如何退出 退出 Qt程序的一般结构如下 int main int argc char
  • 【Java入门杂记】

    文章目录 快捷键 转义符 数据类型 变量 变量名命名规则 交换数值 运算符 逻辑运算符 Scanner 条件语句 循环语句 字符匹配 随机数 二分查找 快捷键 javac与新建系统变量的java路径有关 atl 补齐敏感提示 Ctrl D
  • Java 多线程案例

    多线程解题套路 循环 同步代码块 判断共享数据 已经到末尾 判断共享数据 没有到末尾 案例一 需求 一共有1000张电影票 可以在两个窗口领取 假设每次领取的时间为3000毫秒 请用多线程模拟卖票过程并打印剩余电影票的数量 代码实现 pac
  • CCF CSP认证题目(Python)

    2022 12 1 n i input split n int n i float i sum 0 text list input split for j in range n 1 text j int text j sum text j
  • Vue如何保存当前页面的状态

    Vue如何保存当前页面的状态 0 引言 1 问题的本质探讨 1 1 保留当前页面的状态 1 2 Vue页面的本质 2 问题的解决方案 2 1 组件销毁的情况下传递参数 2 1 1 利用本地存储 2 1 2 利用路由参数 2 2 组件仍在的情
  • 06目标检测-One-stage的目标检测算法

    一 One stage目标检测算法 使用CNN卷积特征 直接回归物体的类别概率和位置坐标值 无region proposal 准确度低 速度相对two stage快 二 One stage基本流程 输入图片 对图片进行深度特征的提取 主干神
  • xml命名空间

    XML命名空间主要完成两件事情 首先 与C 的命名空间一样 它们可以帮助避免命名冲突 当你要合并来自两个不同XML文件的时候这可能会成为一个问题 其次 命名空间赋予了名称一个绝对的意义 例如 名称 nil 可以代表任何意思 然而 如果和ht
  • VuePress学习指南(下)

    VuePress 如何自定义主题和页面布局 要自定义VuePress的主题 需要做以下几步 创建主题文件夹 在VuePress项目的根目录下创建一个themes文件夹 并在其中新建一个以主题名命名的文件夹 例如my theme 创建主题配置
  • Halcon相机标定

    相机标定 相机标定的概念 相机的畸变 相机位置和被拍摄物体位姿关系产生的误差 透镜和成像平面 CMOS 不完全平行 镜头和被拍摄物体不完全平行 标定板 相机标定过程 相机标定的概念 在图像测量过程以及机器视觉应用中 为确定空间物体表面某点的
  • 内部排序算法比较

    问题描述 各种内部排序算法的时间复杂度分析结果只给出了算法执行时间的阶 或大概执行的时间 试通过随机的数据比较各算法的关键字比较次数和关键字移动次数 以取得直观感受 基本要求 对以下10种常用的内部排序算法进行比较 直接插入排序 折半折入排
  • 关于淘宝cnpm 安装后cnpm不是内部或外部命令的解决办法

    今天通过网上查找的教程安装和配置了node环境 接着按照教程安装了cnpm 然而最后运用cnpm v查看版本却出现了如下的错误 不知道是自己在配置环境时出了什么问题 于是上网查了很多解决办法都不行 于是便自己寻找解决的办法 打开node安装
  • C++指向类成员的函数指针

    指向类成员函数的函数指针 定义 类成员函数指针 member function pointer 是 C 语言的一类指针数据类型 用于存储一个指定类具有给定的形参列表与返回值类型的成员函数的访问信息 基本上要注意的有两点 1 函数指针赋值要使