C++ 类成员指针

2023-11-11

1.成员指针简介

成员指针是C++引入的一种新机制,它的申明方式和使用方式都与一般的指针有所不同。成员指针分为成员函数指针和数据成员指针。

2. 成员函数指针

在事件驱动和多线程应用中被广泛用于调用回调函数。在多线程应用中,每个线程都通过指向成员函数的指针来调用该函数。在这样的应用中,如果不用成员指针,编程是非常困难的。成员函数指针的定义格式:

成员函数返回类型 (类名::*指针名)(形参)= &类名::成员函数名

成员指针使用示例:

#include <iostream>
#include <string>
using namespace std;

class A 
{
    string name;

public:
    A(string s) 
    {
        name=s;
    }

    void print() 
    {
        cout<<"name:"<<name<<endl;
    }
};

int main()
{
    A a("lvlv");
    void (A::*memP)()=&A::print; //定义类成员函数指针并赋初值
    (a.*memP)();
}

程序正常运行并输出:

name:lvlv

使用成员函数指着注意两点:
(1)使用成员函数指针时需要指明成员函数所属的类对象,因为通过指向成员函数的指针调用该函数时,需要将对象的地址用作this指针的值,以便进行函数调用;
(2)为成员函数指针赋值时,需要显示使用&运算符,不能直接将“类名::成员函数名”赋给成员函数指针。

3. 数据成员指针

一个类对象生成后,它的某个成员变量的地址实际上由两个因素决定:对象的首地址和该成员变量在对象之内的偏移量

《C++必知必会》的条款15讲述了这一说法:“与常规指针不同,一个指向成员变量的指针并不指向一个内存位置。它指向的是一个类的特定成员,而不是指向一个特定对象里的特定成员。通常最清晰的做法是将指向数据成员的指针看作为一个偏移量。......。这个偏移量告诉你,一个特定成员的位置距离对象的起点有多少个字节。”

数据成员指针是用来保存类的某个数据成员在类对象内的偏移量的。它只能用于类的非静态成员变量。数据成员指针的定义格式:

成员类型 类名::*指针名=&类名::成员名;

数据成员指针使用示例:

#include <iostream>
using namespace std;

class Student
{
public:
    int age;
    int score;
};

double average(Student* objs,int Student::*pm,int count) 
{
    int result=0;
    for(int i=0;i<count;++i)
    {
        result+=objs[i].*pm;
    }
    return double(result)/count;
}

int main()
{
    Student my[3]={{16,86},{17,80},{18,58}};
    double ageAver=average(my,&Student::age,3);            //求平均年龄
    double scoreAver=average(my,&Student::score,3);        //求平均成绩
    cout<<"ageAver:"<<ageAver<<endl;
    cout<<"scoreAver:"<<scoreAver<<endl;
}

程序输出如下结果:

ageAver:17
scoreAver:74.6667

使用数据成员指针时,需要注意以下几点:
(1)数据成员指针作为一个变量,在底层实现上,存放的是对象的数据成员相对于对象首地址的偏移量,因此通过数据成员指针访问成员变量时需要提供对象的首地址,即通过对象来访问。从这个意义上说,数据成员指针并不是一个真正的指针。

(2)对象的数据成员指针可以通过常规指针来模拟,例如上面的程序中,可以讲average()函数的形参pm可以申明为int型变量,表示数据成员的偏移量,那么原来的obj.*pm等同于*(int*)((char*)(&obj)+pm),显然,这样书写可读性差,可移植性低且容易出错。

(3)使用数据成员指针时,被访问的成员往往是类的公有成员,如果是类的私有成员,容易出错。考察如下程序。

#include <iostream>
using namespace std;
class ArrayClass 
{
    int arr[5];
public:
    ArrayClass() 
    {
        for(int i=0;i<5;++i)
            arr[i]=i;
    }
};

//使用数据成员指针作为形参
void printArray(ArrayClass& arrObj,int (ArrayClass::* pm)[5])
{
    for(int i=0;i<5;++i)
    {
        cout<<(arrObj.*pm)[i]<<" ";
    }
}

int main()
{
    ArrayClass arrObj;
    printArray(arrObj,&ArrayClass::arr);//编译出错,提示成员ArrayClass::arr不可访问
}

以上程序无法通过编译,因为成员arr在类ArrayClass中的访问权限设置为private,无法访问。要解决这个问题,将函数printArray()设置为类ArrayClass的友元函数是不行的,因为是在调用该函数时访问了类ArrayClass的私有成员,而不是在函数体内用到类ArrayClass的私有成员。因此,可以定义一个调用printArray()函数的友元函数。该函数的参数中并不需要传递类ArrayClass的私有成员。修改后的程序如下。

#include <iostream>
using namespace std;

class ArrayClass 
{
int arr[5];
public:
    ArrayClass()
    {
        for(int i=0;i<5;++i)
            arr[i]=i;
    }

    friend void print(ArrayClass& arrObj);
};

//使用数据成员指针作为形参
void printArray(ArrayClass& arrObj,int (ArrayClass::* pm)[5]) 
{
    for(int i=0;i<5;++i)
        cout<<(arrObj.*pm)[i]<<" ";
}

//定义友元函数
void print(ArrayClass& arrObj)
{
    printArray(arrObj,&ArrayClass::arr);
}

int main()
{
    ArrayClass arrObj;
    //printArray(arrObj,&ArrayClass::arr);//编译出错,提示成员ArrayClass::arr不可访问
    print(arrObj); //通过友元函数调用打印数组函数printArray()来访问私有成员
}

程序通过编译,运行输出0,1,2,3,4。
 

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

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

  • [Linux安装软件详解系列]01 安装MySQL8.0

    目录 1 检查有没有安装MySQL 2 安装MySQL8 0 1 下载 rpm文件 2 上传rpm文件到服务器 3 安装rpm文件 4 查看安装好的包 5 安装MySQL 5 启动MySQL 3 本地登录 1 查看默认密码 2 本地登录My

随机推荐

  • 这注定是一场独一无二的旅行——周年纪念日 [form 2022 to 2023]

    啊哈 竟然已经一周年了 还记得自己写了两三篇博客以后 就停写了很久 很久 总是因为各种各样的事情拖沓 直到有一天CSDN轻轻敲醒了我沉睡的心灵 忽然意识到自己好久没写了 也让我去想自己的初衷 为何而写 Why 一直觉得内容创作是一个很酷的事
  • 华为OD机试 Python 查找人名

    描述 有一串由逗号分隔的人名 每个人名可能由一个或多个单词组成 请你设计一个方法 根据指定的前缀串 找出与前缀匹配的人名 前缀串的构造是由人名中每个单词的第一个字母组合而成 输入 一串用逗号分隔的人名 一个前缀串 输出 匹配前缀串的所有人名
  • 吴恩达机器学习之路---logistic regression

    logistic regression 一 Logistic 回归 利用matlib实现 基础版 1 logistic regression数学基础 1 1 此示例为二元分类 二元分类的最终预测结果h为 0 1 为获得此效果 使用sigmo
  • 02-----带宽分析-----码流、分辨率、帧率的概念及如何计算视频带宽

    相关文章 01 带宽分析 下载nmon分析软件 一 码流 分辨率 帧率的概念 1 码流 码流 Data Rate 是指视频文件在单位时间内使用的数据流量 也叫码率或码流率 是视频编码中画面质量控制中最重要的部分 一般我们用的单位是Kb s或
  • Java线程学习实例——采用同步锁,互斥锁与同步锁的区别,synchronized的使用方法

    栗子来源 https blog csdn net wenzhi20102321 article details 52524545 首先对java中同步锁与互斥锁进行区分 主要来源于知乎中的大佬总结如下 1 锁的概念 锁的目的就是避免多个线程
  • FTP服务器的文件模式属于,FTP服务器的文件模式属于

    FTP服务器的文件模式属于 内容精选 换一换 在SAP HANA系统中 Shared卷和Backup卷由SFS Turbo提供时 需要创建一个SFS Turbo 提供共享路径给SAP HANA节点 表1列出了弹性文件服务的常用功能 在使用弹
  • uc浏览器解析视频源码,不废话,直接源码

    package cn rs blog service jiexi import com jfinal kit HttpKit import org apache http client CookieStore import org apac
  • 计算时间复杂度--(简单版)

    步骤 1 找到执行次数最多的语句 2 语句执行语句的数量级 3 用O表示结果 计算时间复杂度的3个出发点 掌握这三个出发点 那么一向搞不懂的时间复杂度就可以迎刃而解啦 然后 1 用常数1取代运行时间中的所有加法常数 2 在修改后的运行次数函
  • Spark(火花)快速、通用的大数据处理引擎框架

    一 什么是Spark 火花 是一种快速 通用处理大数据分析的框架引擎 二 Spark的四大特性 1 快速 Spark内存上采用DAG 有向无环图 执行引擎非循环数据流和内存计算支持 内存上比MapReduce快速100倍 磁盘上快10倍左右
  • android surfaceflinger 老罗,「Android」SurfaceFlinger分析

    本篇针对surfaceFlinger模块进行分析 目录如下 1 SurfaceFlinger功能 1 1 BufferQueue原理 native libs gui模块 1 2 layer显示内存分配 native libs ui模块 1
  • 使用org.apache.tools.zip包操作文件

    import java io import org apache tools zip import java util Enumeration 功能 zip压缩 解压 支持中文文件名 说明 本程序通过使用Apache Ant里提供的zip工
  • pytorch中的torchvision.transforms模块详解

    torchvision transforms torchvision transforms是pytorch中的图像预处理包 包含了很多种对图像数据进行变换的函数 这些都是在我们进行图像数据读入步骤中必不可少的 data transforms
  • 最大最小爬山算法的一些总结

    据说MMHC是现行的比较成功的一种混合贝叶斯结构学习算法 其主要思想是 先建立一个贝叶斯网络的骨架 再通过贪心算法确定最终结构 那么要搞懂的是以下 1 框架是如何建立的 2 贪心算法是怎么运行的 3 最大最小体现在哪里 4 为什么会优于一般
  • Linux 关闭无用端口

    Linux 关闭无用端口 关闭系统不必要的端口 增强系统安全 此处以关闭111端口为例进行说明 查看本机正在监听的端口 netstat tlnup 查看正在监听的111端口 由哪个服务使用 cat etc services grep w 1
  • Adobe XD for Mac v35.2.12 界面设计和原型交互工具

    Adobe XD for Mac 是一款优秀的界面设计和原型交互工具 用户可以进行移动应用和网页设计与原型制作 同时它也是唯一一款结合设计与建立原型功能 并同时提供工业级性能的跨平台设计产品 设计师使用Adobe XD可以更高效准确的完成静
  • 继承中析构和构造的调用原则

    继承与组合混搭情况下 构造和析构调用原则 先说结论 原则 先构造父类 再构造成员变量 最后构造自己 先析构自己 在析构成员变量 最后析构父类 注 先构造的对象 后释放 class my 创建一个成员类 public int a my int
  • .Net WebAPI JWT身份验证

    一 开发环境 VS2017 enterprise win10 Pro 64 net 4 6 2 二 开发过程 1 使用VS2017 创建 netframework项目 选择WebApi 2 从Nuget包中搜索并安装JWT 3 在Model
  • 动态路由-BGP的基础配置

    一 给每个路由器配置ip地址 AR6 1 1 添加ip地址 interface GigabitEthernet0 0 0 ip address 1 1 1 1 255 255 255 0 2 配置BGP对等体 bgp 100 配置bgp的A
  • 使用PyQt(Python+Qt)+moviepy开发的视频截取、音视频分离、MP4转GIF动图工具免费下载分享

    专栏 Python基础教程目录 专栏 使用PyQt开发图形界面Python应用 专栏 PyQt入门学习 老猿Python博文目录 在因博文素材需要将软件操作制作成动画时 发现网上相关绿色使用工具都需要注册 否则动态上就会打上各种LOGO 无
  • C++ 类成员指针

    1 成员指针简介 成员指针是C 引入的一种新机制 它的申明方式和使用方式都与一般的指针有所不同 成员指针分为成员函数指针和数据成员指针 2 成员函数指针 在事件驱动和多线程应用中被广泛用于调用回调函数 在多线程应用中 每个线程都通过指向成员