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++ 继承和成员函数指针 的相关文章

  • C# 创建函数队列

    我写了一个名为 QueueManager 的类 class QueueManager Queue functionsQueue public bool IsEmpty get if functionsQueue Count 0 return
  • SharpZipLib - 将文件夹/目录添加到 zip 存档

    通过示例 我很好地掌握了如何提取 zip 文件 几乎在每个示例中 识别 ZipEntry 是否为目录的方法如下 string directoryName Path GetDirectoryName theEntry Name string
  • 使用API​​隐藏程序标题栏

    它可以使用 c 和 windows api 删除窗口控制台标题栏 如果是的话如何 请 这个简单的应用程序隐藏并显示其所在控制台的标题栏 它会立即将控制台标题更改为 guid 以查找窗口句柄 然后 它使用 ToggleTitleBar 使用找
  • C# 中四舍五入到偶数

    我没有看到 Math Round 的预期结果 return Math Round 99 96535789 2 MidpointRounding ToEven returning 99 97 据我了解 MidpointRounding ToE
  • 无法从 Web api POST 读取正文数据

    我正在尝试从新的 Asp Net Web Api 中的请求中提取一些数据 我有一个像这样的处理程序设置 public class MyTestHandler DelegatingHandler protected override Syst
  • 从 future 中检索值时的 SIGABRT

    我在使用 C 11 future 时遇到问题 当我打电话时wait or get 关于返回的未来std async 程序接收从mutex标头 可能是什么问题呢 如何修复它 我在 Linux 上使用 g 4 6 将以下代码粘贴到 ideone
  • 默认值 C# 类 [重复]

    这个问题在这里已经有答案了 我在控制器中有一个函数 并且我收到表单的信息 我有这个代码 public Actionresult functionOne string a string b string c foo 我尝试将其转换为类似的类
  • 无法加载文件或程序集“EntityFramework,版本=6.0.0.0”

    我究竟做错了什么 我该如何解决这个问题 我有一个包含多个项目的解决方案 它是一个 MVC NET 4 5 Web 应用程序 在调试模式下启动后调用其中一个项目时 出现此错误 导致此错误的项目具有以下参考 两个都是版本6 0 0 0 应用程序
  • 防止GDB中的PLT(过程链接表)断点

    在最新版本的 GDB 中 在库函数调用上设置断点会导致多个实际断点 调用过程链接表 PLT 实际的函数调用 这意味着当调用库函数时 我们每次都会经历两次中断 在以前的 GDB 版本中 只会创建 2 因此您只能得到一次中断 那么问题来了 是否
  • 更改 IdentityServer4 实体框架表名称

    我正在尝试更改由 IdentityServer4 的 PersistedGrantDb 和 ConfigurationDb 创建的默认表名称 并让实体框架生成正确的 SQL 例如 而不是使用实体IdentityServer4 EntityF
  • 如何用 C 语言练习 Unix 编程?

    经过五年的专业 Java 以及较小程度上的 Python 编程并慢慢感觉到我的计算机科学教育逐渐消失 我决定要拓宽我的视野 对世界的一般用处 并做一些 对我来说 感觉更重要的事情就像我真的对机器有影响一样 我选择学习 C 和 Unix 编程
  • 系统错误 124 - SHFileOperation 的 ERROR_INVALID_LEVEL

    我在使用时遇到问题SHFileOperation SHFileOperation SHFILEOPSTRUCT https stackoverflow com questions 9191415 shfileoperation shfile
  • JavaScript - 这个这个

    String prototype foo String prototype foo bar function How can you reference the grandparent string console log this par
  • 相当于 C# 中 Java 的“ByteBuffer.putType()”

    我正在尝试通过从 Java 移植代码来格式化 C 中的字节数组 在 Java 中 使用方法 buf putInt value buf putShort buf putDouble 等等 但我不知道如何将其移植到 C 我尝试过 MemoryS
  • 如何将对象转换为传递给函数的类型?

    这不会编译 但我想做的只是将对象转换为传递给函数的 t public void My Func Object input Type t t object ab TypeDescriptor GetConverter t ConvertFro
  • C++ [Windows] 可执行文件所在文件夹的路径[重复]

    这个问题在这里已经有答案了 我需要访问一些文件fstream在我的 Windows 上的 C 应用程序中 这些文件都位于我的exe文件所在文件夹的子文件夹中 获取当前可执行文件的文件夹路径的最简单且更重要的 最安全的方法是什么 Use 获取
  • 如何确保超类的子类方法的线程安全?

    我参加了一次面试 并被要求为以下要求设计一个课程 假设我有一个 A 类 它可以有任意数量的子类 即子类 类 A 有一个名为 doSomething 的方法 该方法是同步的 要求是 A 的所有子类都是强制性的重写 doSomething me
  • 从有符号字符转换为无符号字符然后再转换回来?

    我正在使用 JNI 并有一个 jbyte 类型的数组 其中 jbyte 表示为有符号字符 即范围从 128 到 127 jbyte 表示图像像素 对于图像处理 我们通常希望像素分量的范围为0到255 因此 我想将jbyte值转换为0到255
  • 无法使 Polly 超时策略覆盖 HttpClient 默认超时

    我正在使用 Polly 重试策略 并且正如预期的那样 在重试过程中HttpClient达到 100 秒超时 我尝试了几种不同的方法来合并 Polly 超时策略 将超时移至每次重试而不是总计 但 100 秒超时仍然会触发 我读过大约 5 个
  • 如何在odoo中重写js函数

    我想加载 shop checkout url 函数是 odoo define change info order website sale change info order function require use strict oe w

随机推荐

  • 在导航抽屉 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