【发布时间】:2021-12-04 04:21:42
【问题描述】:
我认为'指向 DerivedT 类型的 T 类成员的指针' 可以用作“指向 BaseT 类型的 T 类成员的指针”很简单 ' 如果 BaseT 是 DerivedT 的基础。类比似乎至少对我来说是显而易见的,因为 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),如果用户想使用它的编译和运行时功能,他们应该从该基类继承。
然后在库中我还有一个接口类:BaseMember,以及它的许多派生类。最终用户可以使用派生类在其用户定义的 DataBinding-descendant 类中添加非静态类成员对象。
在用户代码中,在 DataBinding-descendant 用户类中,用户可以拥有基于 BaseMember 的非静态类成员。这里出现了需要指向成员多态性的新功能:用户应该能够在编译时标记一些基于 BaseMember 的类成员(!)(类本身没有 constexpr 构造函数) - 在我看来'mark' 可以存储指向 BaseMember 后代成员对象的成员的指针,并且只应允许标记的对象在 DataBinding(当前类的 CRTP 基)中运行时调用类成员函数(registerMember)。
在 registerMember 运行时函数中,我有“this”对象指针(包含对象),我有编译时用户定义列表,用于标记启用的指向成员的指针(它可以替换为任何类型的唯一标识) 我有实际的成员指针。我需要检查是否允许实际的成员指针调用该函数(它被标记为编译时间)。
【问题讨论】:
-
因为它是
DerivedT而不是BaseT? -
"as
DerivedT*is aBaseT*" 让我在此阻止你。这是不正确的。在大多数情况下,您可以在需要BaseT*的地方使用DerivedT*,但并非在所有情况下,当然也不是反过来。让我们考虑使用指向数组第一个元素的指针的情况,并且假设DerivedT的大小大于BaseT。DerivedT* array = ...; BaseT* arrayAsBase = array;:您可以使用array[5]来引用数组的第 6 个元素,但访问arrayAsBase[5]是未定义的行为。 -
@Broothy 标准没有指定如何实现指向成员的指针 IIRC。所以很难说指向成员的指针不像函数。
-
也许放弃所有成员都从同一个基类继承的要求会更简单(或在此应用程序中忽略它)。现在您需要创建一个异构的编译时成员指针列表。您可以将它存储在一个元组或一个可变参数类模板中,该模板由实际指向成员的指针值参数化。 (这样你只需要一个异类列表的type,而不是它的值)。
标签: c++ language-lawyer standards member-pointers