C++语法|指向类成员(成员变量和成员方法)的指针及其相关应用场景
文章目录
- 1.基本语法
- 指向成员变量的指针
- 示例
- 指向成员函数的指针
- 示例
- 注意事项
- 2.应用场景
- 泛型编程和模板:通用成员访问打印函数
- 回调机制和事件处理:基于简单GUI框架的事件处理
1.基本语法
指向类成员的指针是一种特殊的指针类型,用于指向类的成员变量或成员函数。与普通指针不同,指向类成员的指针不能单独使用,必须结合特定的类对象来进行访问。
指向成员变量的指针
指向成员变量的指针用于指向某个类的成员变量。其语法如下(重点是要声明作用域):
class A {
public:MemberType member;
};// 定义指向成员变量的指针
MemberType A::*ptr = &A::member;
示例
#include <iostream>
using namespace std;
class MyClass {
public:int data;
}int main() {MyClass obj;obj.data = 10;//定义一个指向成员变量的指针int MyClass::*ptr = &MyClass::data;cout << "data: " << pbj.data << endl;cout << "data using pointer: " << obj.*ptr << endl;
}
指向成员函数的指针
class A {
public:ReturnType Function(Arg);
};// 定义指向成员函数的指针
ReturnType (A::*pointerToFunction)(Arg) = &A::Function;
示例
#include <iostream>
using namespace std;
class MyClass {
public:void display() {cout << "Hello, World!" << endl;}
};
int main () {MyClass obj;void (MyClass::*funcPtr)() = &MyClass::display;//通过对象调用成员函数(obj.*funcPtr)();//通过指针调用成员函数MyClass* objPtr = &obj;(objPtr->*funcPtr)();return 0;
}
注意事项
我们定义一个包含成员方法、静态成员方法、成员变量的类:
一:如何通过指向类成员变量的指针来访问类成员
class Test {
public:void func() { cout << "call Test::func" << endl; }static void static_func() { cout << "Test::static_func" << endl; }static int mb;int ma;
};
int main () {Test t1;//int *p = &Test::ma //报错 无法从“int Test::* ” 转换成 "int *"int Test::*p = &Test::ma;//*p = 20; 报错,因为我们都没有初始化一个 Test对象,类不能脱离对象谈成员//应该先进行初始化,也就是在前面加上 Test t1;t1.*p = 20;
}
总结:普通的成员变量必须依赖一个对象,所以即使操作外部指针也应该依赖一个对象,当然如果我们操作一个静态成员变量,它是不依赖对象的,跟普通指针使用一样
int Test::mb;
int main () {int *p1 = &Test::mb;*p1 = 40; //mb为40
}
二、指向成员方法的指针
我们有一个普通的成员方法void func()
我们如何定义一个函数指针来指向这个函数呢?
int main () {//如果是普通函数中是可以的,但是C++中不被允许//无法从"void (thiscall Test::*)(void)"转换为"void (__cdecl *)(void)"//void(*pfunc)() = &Test::func;//(*pfunc)();Test t1;Test *t2 = new Test();void (Test::*pfunc)() = &Test::func;(t1.*pfunc)(); //通过解引用来调用(t2->*pfunc)();
}
三、指向静态成员方法的指针
跟之前的静态成员变量一样,可以当做一个普通指针来使用,不需要初始化一个类。
静态成员方法的调用不需要依赖一个对象,他就是一个普通的C函数,只不过现在落在了类的作用域里面而已。
2.应用场景
泛型编程和模板:通用成员访问打印函数
在模板编程中,指向成员的指针可以用于编写通用代码,能够操作不同类型对象的成员。这在编写需要操作不同类型对象的函数模板时非常有用。
假设我们有几个不同的类,每个类都有各自不同的成员变量。我们希望编写一个通用的函数,该函数可以接受任何对象和该对象类的任何成员变量的指针,并打印出该成员的值。这种方法在处理多种数据类型的统一处理程序(如日志、序列化、UI显示等)时非常有用。
- 首先我们定义两个示例类:
// 定义两个示例类
class Person {
public:string name;int age;Person(const string& name, int age) : name(name), age(age) {}
};class Product {
public:string title;double price;Product(const string& title, double price) : title(title), price(price) {}
};
- 我们想定义一个通用的打印函数,可以打印不同对象的不同成员
int main() {Person alice("Alice", 30);Product laptop("Laptop", 999.99);// 打印不同对象的不同成员display(alice, &Person::name); // 打印 Person 对象的 name 成员display(alice, &Person::age); // 打印 Person 对象的 age 成员display(laptop, &Product::title); // 打印 Product 对象的 title 成员display(laptop, &Product::price); // 打印 Product 对象的 price 成员return 0;
}
你能帮我编写出来吗?
答案:
//通用的打印函数模板
template<typename T, typename M>
void display(const T&obj, M T::*member) {cout << obj.*member << endl;
}
- 灵活性:printMember 函数可以用于任何类和任何类型的成员变量。
- 重用性:不需要为每种类型或每个成员单独编写打印逻辑。
- 简洁性:代码更加简洁和容易维护,因为成员访问逻辑只编写一次。
回调机制和事件处理:基于简单GUI框架的事件处理
假设我们正在开发一个GUI应用程序,其中包含多个按钮,每个按钮点击时都需要执行不同的操作。我们可以定义一个Button类,该类包含一个成员函数指针,当按钮被点击时,该指针指向的成员函数将被调用。
Step 1: 定义Button类
首先,我们定义一个Button类,它包含一个指向成员函数的指针作为回调。
我们需要定义 Button 类以存储指向成员函数的指针和一个指向调用它的对象的指针。这里的一个关键点是确保成员函数指针的类型正确,并且我们还需要知道哪个类的成员函数将被调用。下面是如何实现这个:
template <typename T>
class Button {
public:using EventCallback = void (T::*)(); // 成员函数指针类型Button() : callbackObject(nullptr), onClick(nullptr) {}// 设置回调函数及其关联的对象void setOnClick(EventCallback callback, T* obj) {onClick = callback;callbackObject = obj;}// 模拟按钮点击void click() {if (callbackObject && onClick) {std::cout << "Button clicked.\n";(callbackObject->*onClick)(); // 使用成员函数指针调用函数}}private:T* callbackObject; // 指向调用成员函数的对象的指针EventCallback onClick; // 成员函数指针
};
Step 2: 定义具体操作
我们定义一个Application类,该类包含多个成员函数,每个函数都可以作为按钮的回调。
class Application {
public:void displayMessage() {std::cout << "Displaying message!\n";}void openFile() {std::cout << "Opening file...\n";}void shutdown() {std::cout << "Shutting down...\n";}
};
Step 3: 绑定事件与成员函数
我们需要将按钮的点击事件绑定到特定的成员函数。这里我们使用std::function和std::bind来完成绑定,因为直接使用指向成员函数的指针需要处理对象的具体实例,而std::function和std::bind提供了更灵活的方式来处理这种情况。
int main() {Application app;Button<Application> btnMessage, btnFile, btnShutdown;// 设置按钮的回调btnMessage.setOnClick(&Application::displayMessage, &app);btnFile.setOnClick(&Application::openFile, &app);btnShutdown.setOnClick(&Application::shutdown, &app);// 模拟按钮点击btnMessage.click();btnFile.click();btnShutdown.click();return 0;
}
总结
这种方式直接使用模板和指向成员函数的指针。此外,它为每个按钮提供了泛型支持,这意味着 Button 类可以与任何类的任何成员函数一起使用,只要这些函数满足返回值 void ,传参()。
使用模板的另一个好处是你可以在编译时捕获类型错误,如尝试绑定到非法函数或不正确的对象。然而,这种方法的限制是它只能与无参数且返回 void 的成员函数一起工作,如果需要更复杂的回调签名,你可能需要修改模板定义来支持这些。
其实,本节比较难的应该是属于函数指针了,但是在C++中常常使用function和bind来替代函数指针的使用场景。。。
扩展阅读:
C语言学习细节|C语言面向对象编程!函数指针如何正确使用
C++语法|可调用对象与function类型
C++语法|bind和function解析并实现一个简易线程池
C++语法|bind1st和bind2nd的用法
相关文章:
C++语法|指向类成员(成员变量和成员方法)的指针及其相关应用场景
文章目录 1.基本语法指向成员变量的指针示例 指向成员函数的指针示例 注意事项 2.应用场景泛型编程和模板:通用成员访问打印函数回调机制和事件处理:基于简单GUI框架的事件处理 1.基本语法 指向类成员的指针是一种特殊的指针类型,用于指向类…...

【C语言】通讯录系统实现
目录 1、通讯录系统介绍 2、代码分装 3、代码实现步骤 3.1制作菜单函数以及游戏运行逻辑流程 3.2、封装人的信息PeoInfo以及通讯录Contact结构体类型 3.3、初始化通讯录InitContact函数 3.4、增加联系人AddContact函数 3.5、显示所有联系人ShowContact函数 3.6、删除联系人D…...
(delphi11最新学习资料) Object Pascal 学习笔记---第12章第1节 ( 类静态方法与Windows API回调)
12.1.4 类静态方法与Windows API回调 静态类方法没有隐藏的Self参数意味着静态类方法可以作为回调函数传递给操作系统(例如,在Windows上)。实际上,您可以声明一个具有stdcall调用约定的静态类方法,并将其用作直接的…...
第一个Rust程序
在安装好Rust以后,我们就可以编写程序了。 首先,我们执行下面的命令,尽量让你的rust版本和我的版本相同,或者比我的版本大。 zhangdapengzhangdapeng:~$ cargo --version cargo 1.78.0 (54d8815d0 2024-03-26) zhangdapengzhangd…...

【LInux】<基础IO> 文件操作 | 文件描述符 | 重定向
👦个人主页:Weraphael ✍🏻作者简介:目前正在学习c和算法 ✈️专栏:Linux 🐋 希望大家多多支持,咱一起进步!😁 如果文章有啥瑕疵,希望大佬指点一二 如果文章对…...
MySQL--增、删、改、查,
数据库的概述、发展、现状、历史、分类 MySQL关系型数据库、架构(C/S) window系统安装MySQL数据库 Linux系统【选学】 数据库对象——数据库(database) show、create、drop命令 数据库对象——表(tableÿ…...

5.12学习总结
一.JAVA聊天室项目 文件发送 使用 Java Socket 实现聊天内容或文件的传输的原理如下: 服务器端启动:聊天室的服务器端在指定的端口上监听客户端的连接。它创建一个 ServerSocket 对象,并通过调用 accept() 方法等待客户端的连接请求。客户…...

ansible利用playbook 部署lamp架构
搭建参考:ansible批量运维管理-CSDN博客 定义ansible主机清单 [rootansible-server ~]# vim /etc/hosts 192.168.200.129 host01 192.168.200.130 host02 [rootansible-server ~]# vim /etc/ansible/hosts [webserver] host01 host02 在ansible端编写index.html…...

SPI通信(使用SPI读写W25Q64)
SPI通信协议 • SPI(Serial Peripheral Interface)是由Motorola公司开发的一种通用数据总线 • 四根通信线: SCLK:串行时钟线,用来提供时钟信号的。 MOSI:主机输出,从机输入 MISO:从机输出,主机输入 SS:…...
<sa8650>QCX Usecase 使用详解—拓扑图 XML 定义
<sa8650>QCX Usecase 使用详解—拓扑图 XML 定义 一 、前言二、拓扑图 XML 定义2.1 <Node, port, link>2.2 < XML prolog >2.3 < UsecaseDef >2.4 < Usecase>2.5 < Targets>2.5.1 < Target>2.5.2 < Range>2.6 < Pipeline>2.…...
使用C++11实现Golang的defer功能
本文主要用C11标准来实现Golang的defer功能。 背景 目前笔者的主力语言是Golang,其次是C,再次是JS、Delphi。在Golang工程中大量使用了defer关键字实现函数的延迟调用。如打开文件的出错处理。近来在C工程中遇到类似需求,在函数返回时进行某…...

前端之电力系统SVG图低代码
其实所有的图形都是由点,线,面组成的。点线面可以组成一个设备。下面就简单讲讲点线面是怎么画的吧 对于线,可以用path <g><path:d"M ${beginX},${beginY} L ${endX},${endY}":stroke-width"lineWidth":strok…...

括号生成[中等]
优质博文:IT-BLOG-CN 一、题目 数字n代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。 示例 1: 输入:n 3 输出:["((()))","(()())","(())(…...
配置ubuntu的VNC时遇到报错_XSERVTransmkdir: Mode of /tmp/.X11-unix should be set to 1777
现在win11内嵌了ubuntu系统,我在根据打造基于 VNC 的 Ubuntu 20.04 的远程桌面 配置VNC server时,到了 vncserver :1 这一步,遇到报错: vncserver: /usr/bin/Xtigervnc did not start up, please look into /root/.vnc/xxxxx.:1.…...

openstack部署nova中出现的问题:
[rootcontroller nova]# su -s /bin/sh -c “nova-manage db sync” nova /usr/lib/python2.7/site-packages/pymysql/cursors.py:170: Warning: (1831, u’Duplicate index block_device_mapping_instance_uuid_virtual_name_device_name_idx. This is deprecated and will be…...
【OpenCV 基础知识 3】边缘检测
文章目录 cvCanny完整示例代码 cvCanny 这行代码使用OpenCV库中的 cvCanny 函数对灰度图像进行边缘检测。让我解释一下: cvCanny(gray, dst, 10, 100, 3);gray: 这是输入的灰度图像,即要进行边缘检测的图像。dst: 这是输出的边缘图像,即将结…...
拓宽知识储备量(指数级成长)
对于增强自己的知识储备,不是什么知识都往脑袋里去塞,最好的办法就是让自己的心态回到自己初心的时候,始终保值一颗学者的心,你像那些成功人士,比如格力,华为,腾讯等这样的大公司创始人哪个不是…...

x264 帧类型代价计算原理:slicetype_mb_cost 函数分析
slicetype_mb_cost 函数 函数功能 计算每个宏块 MB 的代价 cost。函数参数分析 x264_t *h:全局编码结构体x264_mb_analysis_t *a:宏块分析结构体x264_frame_t **frames:系列帧数据结构体int p0:帧序号之一,一般指向靠前帧int p1:帧序号之一,一般指向靠后帧int b:帧标志…...

战网国际服加速器哪个好用 暴雪战网免费加速器分享
战网国际服(Battle.net International或Battle.net Global)是由暴雪娱乐公司(Blizzard Entertainment)运营的面向全球玩家的多人在线游戏平台。与专注于特定地区的版本不同,国际服允许玩家不受地域限制地访问暴雪的多款…...

Java入门基础学习笔记26——break,continue
跳转关键字: break: 跳出并结束当前所在循环的执行。 continue: 用于跳出当前循环中的当次执行,直接进入循环中的下一次执行。 package cn.ensource.loop;public class BreakContinueDemo8 {public static void main(String[] a…...

第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...

微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...

面向无人机海岸带生态系统监测的语义分割基准数据集
描述:海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而,目前该领域仍面临一个挑战,即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...

uniapp 开发ios, xcode 提交app store connect 和 testflight内测
uniapp 中配置 配置manifest 文档:manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号:4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...
uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)
UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件) 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式: 标准消息类型:直接使用 SDK 内置类型(文件、图片等)自…...