c++ - 了解指向类型类成员的指针 - 无多态性

标签 c++ language-lawyer standards member-pointers

我认为很简单,如果 BaseT 是 DerivedT 的基类,则可以将“指向类型为 DerivedT 的类 T 的成员的指针”用作“指向类型为 BaseT 的类 T 的成员的指针”。类比似乎至少对我来说是显而易见的,因为 DerivedT* 可以用作 BaseT*,因此 DerivedT T::* 应该能够用作 BaseT T::*
但事实并非如此:

struct BaseT
{
};

struct DerivedT: public BaseT
{
};

struct T 
{
    DerivedT m_test;
};

using BaseTMemPtr = BaseT T::*;

int main()
{
    T test;
    BaseT* simplePtr = &test.m_test; //It is DerivedT*, but can be used as BaseT*
    BaseT (T::*memPtr) = &T::m_test; //Error, BaseT T::* cannot be used as DerivedT T::*
    BaseTMemPtr memPtr2 = &T::m_test; //Error, just the same
}
正如我所见,有两种方法可以解释指向类成员的指针:
  • DerivedT T::* 是一个 DerivedT 指针,它指向 T 类对象内的 DerivedT 对象(因此指向一个对象相对于另一个对象)
  • DerivedT T::* 指向类 T 的对象的某个部分,顺便说一下 DerivedT 类型。

  • 所以这两种方式的主要区别在于,第一种可以解释为一种 DerivedT 指针(启用多态性),而后一种则丢弃类型并限制使用很多。
    为什么 C++ 选择了第二种方法?启用使用 DerivedT T::* 作为 BaseT T::* 会产生什么不良后果?在实践中指向成员的指针是什么?
    更新:
    我想实现以下目标:
    Desired solution
    但如果成员不是 BaseMember 类型而是 BaseMember 后代,则它不起作用。
    如果我使用 BaseMembers(但在这种情况下我无法实现所需的成员功能),则该概念有效:
    Works with broken functionality
    更新 2:为什么
    TLDR:
    一种编译时“标记”(唯一标识)运行时构造类的非静态成员对象的方法。然后检查常规(非成员)指针是否在具有编译时标记的运行时函数中
    1、标记成员的编译时数组(可以是任何东西,在我看来是多态的成员指针)
    2.包含对象的'this'指针(具有标记和未标记的成员)
    3、常规(non-pointer-to-member)指向非静态成员对象的指针。
    时间轴:类定义(编译时)-> 添加类成员(编译时)-> 将类成员标记为已启用-例如在数组中-(编译时)-> 构造(运行时)-> 成员将调用注册函数(运行时)-> 在注册函数中,我们需要检查是否允许调用者(我们将其作为常规指针接收)调用它功能与否(运行时)。
    详细说明:
    在一个库中,我有一个 CRTP 基类(DataBinding),如果用户想使用它的编译和运行时功能,他们应该继承它。
    然后在库中我还有一个接口(interface)类:BaseMember,以及它的许多派生类。最终用户可以使用派生类在其用户定义的 DataBinding 后代类中添加非静态类成员对象。
    在用户代码中,在 DataBinding 后代用户类中,用户可以拥有基于 BaseMember 的非静态类成员。这里出现了需要成员指针多态性的新功能:用户应该能够在编译时标记一些基于 BaseMember 的类成员(!)(类本身没有 constexpr 构造函数) - 在我看来这'mark' 可以存储指向 BaseMember 后代成员对象的成员的指针 - 并且只有被标记的对象应该被允许运行时调用 DataBinding(当前类的 CRTP 基类)中的类成员函数(registerMember)。
    在 registerMember 运行时函数中,我有“this”对象指针(包含对象),我有编译时用户定义的列表,该列表标记了启用的成员指针(它可以用任何类型的唯一标识替换),并且我有实际的成员指针。我需要检查是否允许实际成员指针调用该函数(它被标记为编译时)。

    最佳答案

    指向数据成员的指针通常由一个简单的整数值表示,告诉所有者类的开头到成员开头的偏移量。因此,在给定指向其所有者的指针的情况下检索数据成员的算法就像“将偏移量添加到地址并取消引用”一样简单。
    然而,为了从指向派生的指针到指向基的指针,这样简单的描述是不够的。由于虚拟继承,偏移量不一定是恒定的。为了找到偏移量,我们需要一个实际的派生对象。偏移量存储在某处。因此,在一般情况下,指向数据成员的指针必须表示为至少两个偏移量的组合,并且获取成员需要做出决定(是否存在虚拟基?)
    我想标准本可以只为非虚拟继承情况提供这种转换。在这种情况下,偏移量是恒定的,转换将包括添加两个偏移量(除非我错过了其他一些极端情况)。然而,这并没有完成,原因当然是没有人觉得有足够的动力来写一份提案。指向数据成员的指针(与指向成员函数的指针相反)最初被 Stroustrup 认为是“泛化的产物,而不是真正有用的东西”(D&E,13.11 指向成员的指针)。它们现在(主要)用于以独立于实现的方式描述类布局,但实际上没有必要以多态方式使用它们。

    关于c++ - 了解指向类型类成员的指针 - 无多态性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69593587/

    相关文章:

    c++ - 空基类是否会影响派生类的布局?

    css - 为什么 CSS 不支持常量?

    c - "int"真的需要至少与 C 中的 "short"一样大吗?

    c++ - 设计可定制的字符串过滤器

    c++ - 合并 char 得到 char*

    c++ - 如何避免为聚合初始化重新输入类型信息?

    c - C中的翻译单元到底是什么

    c++ - 在 C++ 中使用 random.h 和 card.h 制作卡片

    python - 如何将这行 Python 转换为 C++?

    fortran - 函数求值与语句中的其他效果冲突