C++ 继承和成员函数指针

2024-03-21

在C++中,成员函数指针可以用来指向派生(甚至基)类成员吗?

编辑: 也许一个例子会有所帮助。假设我们有一个由三个类组成的层次结构X, Y, Z按照继承顺序。Y因此有一个基类X和一个派生类Z.

现在我们可以定义一个成员函数指针p上课Y。写成:

void (Y::*p)();

(为简单起见,我假设我们只对具有签名的函数感兴趣void f() )

这个指针p现在可以用来指向类的成员函数Y.

这个问题(实际上是两个问题)是:

  1. Can p用于指向派生类中的函数Z?
  2. Can p用于指向基类中的函数X?

C++03 标准,§4.11 2 成员指针转换 http://www.open-std.org/jtc1/sc22/WG21/docs/wp/html/nov97-2/conv.html#conv.mem:

An rvalue of type “pointer to member of B of type cv T,” where B is a class type, can be converted to an rvalue of type “pointer to member of D of type cv T,” where D is a derived class (clause 10) of B. If B is an inaccessible (clause 11), ambiguous (10.2) or virtual (10.1) base class of D, a program that necessitates this conversion is ill-formed. The result of the conversion refers to the same member as the pointer to member before the conversion took place, but it refers to the base class member as if it were a member of the derived class. The result refers to the member in D’s instance of B. Since the result has type “pointer to member of D of type cv T,” it can be dereferenced with a D object. The result is the same as if the pointer to member of B were dereferenced with the B sub-object of D. The null member pointer value is converted to the null member pointer value of the destination type. 52)

52)The rule for conversion of pointers to members (from pointer to member of base to pointer to member of derived) appears inverted compared to the rule for pointers to objects (from pointer to derived to pointer to base) (4.10, clause 10). This inversion is necessary to ensure type safety. Note that a pointer to member is not a pointer to object or a pointer to function and the rules for conversions of such pointers do not apply to pointers to members. In particular, a pointer to member cannot be converted to a void*.

简而言之,您可以将指向可访问的非虚拟基类成员的指针转换为指向派生类成员的指针,只要该成员不模糊即可。

class A {
public: 
    void foo();
};
class B : public A {};
class C {
public:
    void bar();
};
class D {
public:
    void baz();
};
class E : public A, public B, private C, public virtual D {
public: 
    typedef void (E::*member)();
};
class F:public E {
public:
    void bam();
};
...
int main() {
   E::member mbr;
   mbr = &A::foo; // invalid: ambiguous; E's A or B's A?
   mbr = &C::bar; // invalid: C is private 
   mbr = &D::baz; // invalid: D is virtual
   mbr = &F::bam; // invalid: conversion isn't defined by the standard
   ...

另一个方向的转换(通过static_cast)由§ 5.2.9 http://www.open-std.org/jtc1/sc22/WG21/docs/wp/html/nov97-2/expr.html#expr.static.cast 9:

An rvalue of type "pointer to member of D of type cv1 T" can be converted to an rvalue of type "pointer to member of B of type cv2 T", where B is a base class (clause 10 class.derived http://www.open-std.org/jtc1/sc22/WG21/docs/wp/html/nov97-2/derived.html#class.derived) of D, if a valid standard conversion from "pointer to member of B of type T" to "pointer to member of D of type T" exists (4.11 conv.mem http://www.open-std.org/jtc1/sc22/WG21/docs/wp/html/nov97-2/conv.html#conv.mem), and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1.11) The null member pointer value (4.11 conv.mem http://www.open-std.org/jtc1/sc22/WG21/docs/wp/html/nov97-2/conv.html#conv.mem) is converted to the null member pointer value of the destination type. If class B contains the original member, or is a base or derived class of the class containing the original member, the resulting pointer to member points to the original member. Otherwise, the result of the cast is undefined. [Note: although class B need not contain the original member, the dynamic type of the object on which the pointer to member is dereferenced must contain the original member; see 5.5 expr.mptr.oper http://www.open-std.org/jtc1/sc22/WG21/docs/wp/html/nov97-2/expr.html#expr.mptr.oper.]

11) Function types (including those used in pointer to member function types) are never cv-qualified; see 8.3.5 dcl.fct http://www.open-std.org/jtc1/sc22/WG21/docs/wp/html/nov97-2/decl.html#dcl.fct.

简而言之,您可以从派生的转换D::*到一个基地B::*如果你可以从B::* to a D::*,尽管您只能使用B::*位于 D 类型或 D 后代的对象上。

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

C++ 继承和成员函数指针 的相关文章

  • 以文化中立的方式将字符串拆分为单词

    我提出了下面的方法 旨在将可变长度的文本拆分为单词数组 以进行进一步的全文索引处理 删除停止词 然后进行词干分析 结果似乎不错 但我想听听关于这种实现对于不同语言的文本的可靠性的意见 您会建议使用正则表达式来代替吗 请注意 我选择不使用 S
  • GLKit的GLKMatrix“列专业”如何?

    前提A 当谈论线性存储器中的 列主 矩阵时 列被一个接一个地指定 使得存储器中的前 4 个条目对应于矩阵中的第一列 另一方面 行主 矩阵被理解为依次指定行 以便内存中的前 4 个条目指定矩阵的第一行 A GLKMatrix4看起来像这样 u
  • 秒表有最长运行时间吗?

    多久可以Stopwatch在 NET 中运行 如果达到该限制 它会回绕到负数还是从 0 重新开始 Stopwatch Elapsed返回一个TimeSpan From MSDN https learn microsoft com en us
  • 不支持将数据直接绑定到存储查询(DbSet、DbQuery、DbSqlQuery)

    正在编码视觉工作室2012并使用实体模型作为我的数据层 但是 当页面尝试加载时 上面提到的标题 我使用 Linq 语句的下拉控件往往会引发未处理的异常 下面是我的代码 using AdventureWorksEntities dw new
  • 查找c中结构元素的偏移量

    struct a struct b int i float j x struct c int k float l y z 谁能解释一下如何找到偏移量int k这样我们就可以找到地址int i Use offsetof 找到从开始处的偏移量z
  • PHP 接口有属性吗?

    PHP 中的接口有属性 还是只有方法 您可以在 DocBlock 中为接口声明属性 然后 IDE 将提示接口的这些属性 PhpStorm 会这样做 但这不会强制在实现类中实际实现这些字段 例如 property string passwor
  • 嵌套接口:将 IDictionary> 转换为 IDictionary>?

    我认为投射一个相当简单IDictionary
  • 如何从 appsettings.json 文件中的对象数组读取值

    我的 appsettings json 文件 StudentBirthdays Anne 01 11 2000 Peter 29 07 2001 Jane 15 10 2001 John Not Mentioned 我有一个单独的配置类 p
  • 不同枚举类型的范围和可转换性

    在什么条件下可以从一种枚举类型转换为另一种枚举类型 让我们考虑以下代码 include
  • 将 VSIX 功能添加到 C# 类库

    我有一个现有的单文件生成器 位于 C 类库中 如何将 VSIX 项目级功能添加到此项目 最终目标是编译我的类库项目并获得 VSIX 我实际上是在回答我自己的问题 这与Visual Studio 2017 中的单文件生成器更改 https s
  • 创建链表而不将节点声明为指针

    我已经在谷歌和一些教科书上搜索了很长一段时间 我似乎无法理解为什么在构建链表时 节点需要是指针 例如 如果我有一个节点定义为 typedef struct Node int value struct Node next Node 为什么为了
  • 将多个表映射到实体框架中的单个实体类

    我正在开发一个旧数据库 该数据库有 2 个具有 1 1 关系的表 目前 我为每个定义的表定义了一种类型 1Test 1Result 我想将这些特定的表合并到一个类中 当前的类型如下所示 public class Result public
  • Windows 窗体:如果文本太长,请添加新行到标签

    我正在使用 C 有时 从网络服务返回的文本 我在标签中显示 太长 并且会在表单边缘被截断 如果标签不适合表单 是否有一种简单的方法可以在标签中添加换行符 Thanks 如果您将标签设置为autosize 它会随着您输入的任何文本自动增长 为
  • 对现有视频添加水印

    我正在寻找一种用 C 在视频上加水印的方法 就像在上面写文字一样 图片或文字标签 我该怎么做 谢谢 您可以使用 Nreco 视频转换器 代码看起来像 NReco VideoConverter FFMpegConverter wrap new
  • 如何从两个不同的项目中获取文件夹的相对路径

    我有两个项目和一个共享库 用于从此文件夹加载图像 C MainProject Project1 Images 项目1的文件夹 C MainProject Project1 Files Bin x86 Debug 其中有project1 ex
  • 为什么编译时浮点计算可能不会得到与运行时计算相同的结果?

    In the speaker mentioned Compile time floating point calculations might not have the same results as runtime calculation
  • 如何在Xamarin中删除ViewTreeObserver?

    假设我需要获取并设置视图的高度 在 Android 中 众所周知 只有在绘制视图之后才能获取视图高度 如果您使用 Java 有很多答案 最著名的方法之一如下 取自这个答案 https stackoverflow com a 24035591
  • 基于 OpenCV 边缘的物体检测 C++

    我有一个应用程序 我必须检测场景中某些项目的存在 这些项目可以旋转并稍微缩放 更大或更小 我尝试过使用关键点检测器 但它们不够快且不够准确 因此 我决定首先使用 Canny 或更快的边缘检测算法 检测模板和搜索区域中的边缘 然后匹配边缘以查
  • C# - OutOfMemoryException 在 JSON 文件上保存列表

    我正在尝试保存压力图的流数据 基本上我有一个压力矩阵定义为 double pressureMatrix new double e Data GetLength 0 e Data GetLength 1 基本上 我得到了其中之一pressur
  • Windows 和 Linux 上的线程

    我在互联网上看到过在 Windows 上使用 C 制作多线程应用程序的教程 以及在 Linux 上执行相同操作的其他教程 但不能同时用于两者 是否存在即使在 Linux 或 Windows 上编译也能工作的函数 您需要使用一个包含两者的实现

随机推荐

  • 在导航抽屉 Android 上添加 EditText

    我正在开发一个带有导航抽屉的新应用程序 使用 Android 模板 但我想用其他视图替换默认的列表视图 SOLVED 我必须编辑 java 代码来修改 createView 方法以与我的布局匹配 谢谢大家 问题 我的班级从ActionBar
  • 如何使用 Rustup 删除 Rust 编译器工具链?

    Rustup 文档展示了如何每晚安装 Rust https github com rust lang nursery rustup rs working with nightly rust 但不知道如何删除它 虽然文档确实显示了如何卸载ru
  • ArrayList 与通用集合

    在 NET 2 0 中使用 ArrayList 代替泛型集合有何优缺点 通用集合是类型安全的 你不能将string into a List
  • 核心数据 - 基本问题

    我想知道以下内容在 Objective C 中是如何工作的 在我的头文件中 我有以下内容 它是从不同的视图控制器初始化的 interface UserLookup UIViewController NSManagedObjectContex
  • 如何实现设备端CUDA虚拟功能?

    我发现 CUDA 不允许将具有虚拟函数的类传递到内核函数中 对于这个限制有什么解决方法吗 我真的很希望能够在内核函数中使用多态性 Thanks 罗伯特 克罗维拉评论中最重要的部分是 只需在设备上创建对象即可 所以记住这一点 我正在处理我有一
  • jQuery UI 和分割器

    使用 jQuery UI 我如何使用类似 Splitter 的功能http methvin com splitter 3csplitter html http methvin com splitter 3csplitter html 我问这
  • 如何同时运行不同版本的node.js?

    我已经为我的 cloud9 应用程序安装了节点 v0 8 25 并且我想在节点 v0 11 2 上进行开发 那么我可以在 v0 8 上运行 cloud9 并在 Ubuntu 上的 v0 11 2 上运行我的程序吗 我用的是nvm Thank
  • 带有 Google Apps 脚本的 jQuery UI

    是否可以将 jQuery UI 小部件与 google apps 脚本应用程序一起使用 我有一个文本框 我想在上面使用日期选择器 是的 您可以将 JQueryUI 与 Google Apps 脚本一起使用 我建议您查看示例代码 您无需执行任
  • TypeScript 中未检查“void”返回类型 – 防止浮动承诺?

    在 TypeScript 3 9 7 中运行 这与编译器无关 const someFn gt void gt 123 我发现这个答案 https stackoverflow com a 12763878 2072165 这说明这是设计使然
  • org.eclipse.debug.core.DebugException:com.sun.jdi.ClassNotLoadedException:检索数组的组件类型时发生类型未加载

    我正在开发AuthSample示例使用chase paymentech Java SDK命名为 PaymentechSDK jar version 7 4 0 当我尝试执行示例代码时 遇到以下错误 我不明白有什么问题 有人可以指导我吗 FY
  • 为什么空数组在 bash 中被视为未设置?

    最近 我设置了微软的Linux 的 Windows 子系统 https en wikipedia org wiki Windows Subsystem for Linux在我的电脑上 它只是模拟 Linux 环境等 基本上 它是 Cygwi
  • Twig 无法调用字符串变量上的方法

    更新后 twig twig to v2 4 4 调用宏函数时出错 Impossible to invoke a method widget prototype on a string variable ERP timesheets form
  • 以“is”为前缀的布尔属性名称仍然是有效的 Java Bean 吗?

    我刚刚注意到一些我不知道的事情 private boolean isCertified public boolean isCertified return isCertified public void setCertified boole
  • 如何最好地避免 C++/CLI 本机类型中的双重转换

    传统上 我一直使用 MFC 扩展 dll 并使用 dllimport dllexport 导入 导出 但是 当 dll 更改为使用 clr 时 此方法的成本会变得很高 因为调用可能会导致双重转换 我现在的性能受到了巨大的打击 需要停止双重重
  • 使用 DOMXml 和 Xpath 更新 XML 条目

    您好 我知道这里有很多关于这三个主题组合在一起更新 XML 条目的问题 但似乎每个人都针对给定的问题 我花了一些时间试图理解 XPath 及其方式 但我仍然无法得到我需要做的事情 开始了 我有这个 XML 文件
  • 如何从 ExtJS 数据存储中获取脏记录?

    除了迭代存储中的记录并检查脏标志之外 还有更干净的方法吗 EDIT 顺便说一句 我正在使用 ExtJS4 这是返回的数据的片段 注意有一个dirty true与modified对象集 实际上是旧数据和data对象包含新数据 data Ext
  • 将工具提示设置为相同的内容

    我试图将数据网格单元格工具提示设置为等于该单元格中 TextBlock 内部的文本 到目前为止我所拥有的是这样的
  • 为什么 Java 支持秒精度的时区偏移?

    在维基百科上 https en wikipedia org wiki ISO 8601 Time offsets from UTC时区偏移被解释为与标准 UTC 时间之间的小时和分钟差异 然而 日期时间格式化程序 https docs or
  • Xcode 4 配置为使用更少的 RAM?

    我一直在尝试在我的 1GB Mac Mini 上使用 Xcode 4 这不是一个令人高兴的情况 它经常变慢 可能是由于内存不足 是否有任何我可以更改的设置 这样它就不会如此占用内存 另一个帖子here https stackoverflow
  • C++ 继承和成员函数指针

    在C 中 成员函数指针可以用来指向派生 甚至基 类成员吗 编辑 也许一个例子会有所帮助 假设我们有一个由三个类组成的层次结构X Y Z按照继承顺序 Y因此有一个基类X和一个派生类Z 现在我们可以定义一个成员函数指针p上课Y 写成 void