我认为如果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:: *可能会产生什么不良后果?在实践中指向成员的指针是什么?
更新: 我想实现以下目标: 所需的解决方案 但如果成员不是 BaseMember 类型而是 BaseMember 后代,则它不起作用。如果我使用 BaseMembers,则该概念有效(但在这种情况下,我无法实现所需的成员功能): 适用于损坏的功能
更新 2:为什么
TLDR:
一种编译时间“标记”(唯一标识)运行时构造类的非静态成员对象的方法。然后检查一个常规(非成员)指针是否在具有
1的运行时函数中被编译时标记,标记成员的编译时间数组(可以是任何东西,在我看来是指向成员的多态指针)
2. 包含对象(具有标记和未标记成员)的“this”指针
3,指向非静态成员对象的常规(非指向成员)指针。
时间轴:类定义(编译时)->添加类成员(编译时)->将类成员标记为启用-例如在数组中-(编译时)->构造(运行时)->成员将调用注册函数(运行时) -> 在注册函数中,我们需要检查调用者(我们将其作为常规指针接收)是否允许调用此函数(运行时)。
详细描述:
在一个库中,我有一个 CRTP 基类(DataBinding),如果用户想使用它的编译和运行时功能,他们应该继承它。然后在库中我还有一个接口类:BaseMember,以及它的许多派生类。最终用户可以使用派生类在其用户定义的 DataBinding 子类中添加非静态类成员对象。
在用户代码中,在 DataBinding-descendant 用户类中,用户可以拥有基于 BaseMember 的非静态类成员。这里出现了需要指向成员多态性的新功能:用户应该能够在编译时标记一些基于 BaseMember 的类成员(!)(类本身没有 constexpr 构造函数) - 在我看来'mark' 可以存储指向 BaseMember 后代成员对象的成员的指针,并且只应允许标记的对象在 DataBinding(当前类的 CRTP 基)中运行时调用类成员函数(registerMember)。
在 registerMember 运行时函数中,我有“this”对象指针(包含对象),我有编译时用户定义的列表,它标记了启用的指向成员的指针(它可以用任何类型的唯一标识替换),我有实际的成员指针。我需要检查是否允许实际的成员指针调用该函数(它被标记为编译时间)。