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

Understanding pointer to member of class of type - no polymorphism

我认为“指向 DerivedT 类型的 class T 成员的指针”可以用作“指向如果 BaseTDerivedT 的基础,则类型为 BaseT 的 class 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
}

据我所知,有两种方法可以解释指向 class 成员的指针:

  1. DerivedT T::* 是一个指向 DerivedT 对象的 DerivedT 指针在 T class 的对象内(因此指向一个对象相对于另一个对象)
  2. DerivedT T::* 指向 class T 对象的某个部分,顺便说一句 DerivedT类型.

所以这两种方式的主要区别在于,第一种可以解释为一种 DerivedT 指针(启用多态性),而后一种则丢弃类型并严格限制使用。

为什么C++选择第二种方式?将 DerivedT T::* 用作 BaseT T::* 可能会产生什么不良后果?实践中成员的指针是什么?

更新: 我想实现以下目标: Desired solution 但如果成员不是 BaseMember 类型而是 BaseMember 后代,则它不起作用。 如果我使用 BaseMembers,这个概念就有效(但在这种情况下我无法实现所需的成员功能): Works with broken functionality

更新 2:为什么
TLDR:
编译时'mark'(唯一标识)一个运行时构造的非静态成员对象的方法class。然后检查常规(非成员)指针是否在具有
的运行时函数中被编译时标记 1,标记成员的编译时数组(可以是任何东西,在我看来是多态成员指针)
2. 'this' 包含对象(具有标记和未标记成员)的指针
3、常规(non-pointer-to-member)指向非静态成员对象的指针。

时间轴:class 定义(编译时)-> 添加 class 成员(编译时)-> 将 class 成员标记为已启用 - 例如在数组中-(编译时)->构造(运行时)->成员将调用注册函数(运行时)->在注册函数中,我们需要检查是否允许调用者(我们将其作为常规指针接收)调用它功能与否(运行时)。

详细说明:
在一个库中,我有一个 CRTP 基础 class (DataBinding),如果用户想使用它的编译和运行时功能,他们应该继承它。 然后在库中我还有一个接口 class: BaseMember,以及它的许多派生 classes。最终用户可以使用派生的 classes 在其用户定义的 DataBinding-descendant classes.

中添加非静态 class 成员对象

在用户代码中,在 DataBinding-descendant 用户 classes 中,用户可以拥有基于 BaseMember 的非静态 class 成员。这里出现了需要指向成员多态性的指针的新功能:用户应该能够在编译时标记一些基于 BaseMember 的 class 成员(!)(class 本身没有constexpr 构造函数)——在我看来,这个 'mark' 可以存储指向 BaseMember 后代成员对象成员的指针——并且只有标记的对象才允许运行时调用 class 成员函数(registerMember) in DataBinding (当前class的CRTP基础).

在 registerMember 运行时函数中,我有“this”对象指针(包含对象),我有编译时用户定义列表,标记已启用的指向成员的指针(它可以替换为任何类型的唯一标识)并且我有实际的成员指针。我需要检查是否允许实际成员指针调用函数(它被标记为编译时)。

指向数据成员的指针通常由一个简单的整数值表示,告诉所有者 class 开头到成员开头的偏移量。因此,在给定指向其所有者的指针的情况下检索数据成员的算法就像“将偏移量添加到地址并取消引用”一样简单。

但是,为了从派生指针到基指针,这样简单的描述是不够的。由于虚拟继承,偏移量不一定是常量。为了找到偏移量,我们需要一个实际的派生对象。偏移量存储在某处。所以在一般情况下,指向数据成员的指针必须表示为至少两个偏移量的组合,并且获取成员需要一个决定(是否存在虚拟基?)

我想该标准可能只为非虚拟继承情况提供了这种转换。在这种情况下,偏移量是常量,转换将包括添加两个偏移量(除非我遗漏了一些其他极端情况)。然而,这并没有被完成,原因当然是没有人有足够的动力写一份提案。指向数据成员的指针(与指向成员函数的指针相反)最初被 Stroustrup 认为是“泛化的产物,而不是真正有用的东西”(D&E,13.11 Pointers to Members)。它们现在(主要)用于以独立于实现的方式描述 class 布局,但实际上没有必要以多态方式使用它们。