向上转换指向数据成员及其多态行为的指针
Upcasting a pointer to data member and its polymorphic behavior
我试图将指向派生类的数据成员的指针强制转换为指向基类的数据成员的指针,但以下代码无法编译:
class Base
{
public:
virtual void f() {}
};
class Derived : public Base
{
public:
void f() override {}
};
class Enclosing
{
public:
Derived member;
};
int main()
{
Derived Enclosing::*p = &Enclosing::member;
auto bp = static_cast<Base Enclosing::*>(p); // compile error
}
所以我改用了reinterpret_cast
,代码编译:
auto bp = reinterpret_cast<Base Enclosing::*>(p); // passes compile
我试图直接使用bp
:
Enclosing instance;
(instance.*bp).f(); // calls Base::f
这不是我所期望的,因为Enclosing
中的成员实际上是Derived
类型。 然后我试了这个:
(&(instance.*bp))->f(); // calls Derived::f
它适用于我的环境,但这种行为是否得到保证?
你不能拥有你想要的。只有在以下情况下,您才能获得数据成员的多态性:pointer to member of D of type T
转换为pointer of member of B of type T
其中B
是D
的基类。
您想要的,不允许将pointer to member of X of type T1
转换为pointer to member of X of type T2
或未定义的行为。
要实现多态性,您需要这样的东西:
Enclosing e;
Derived Enclosing::* d = &Enclosing::d;
Base* b = &(e.*d);
return b->foo(); // calls Derived::foo
§4 标准转换 [转换]
标准转换是具有内置含义的隐式转换。
§4.11 指向成员转换的指针 [conv.mem]
空指针常量 (4.10) 可以转换为指向成员类型的指针。[...]
类型为"指向 cv T 类型的 B 的成员的指针"的 prvalue,其中 B 是类类型,可以转换为类型为 "指向成员的指针" 的 prvalue cv T类型的D",其中D是B的派生类(第10条)。
因此,我们看到,对于标准转换(隐式转换),不允许进行转换
§5.2.9 静态强制转换
类型为 "指向
- cv1 T 的 D 成员的指针"类型的 prvalue 可以转换为 cv2 T 类型的 "指向 B 的成员的指针" 类型的 prvalue, 其中 B 是 D 的基类(第 10 条),如果是有效的标准 从"指向类型 T 的 B 成员的指针"转换为"指向 存在 T" 的 D 成员 (4.11),并且 cv2 相同 CV资格为CV1,或比CV1更高的CV资格。[...]
对于static_cast
我们看到基本上只允许指向成员转换的指针进行标准转换。这就是您观察到的,static_cast
是编译器错误。
§ 5.2.10 重新解释演员表 [exr.reinterpret.cast]
类型为"指向类型 T1 的 X 的成员的指针"的 prvalue 可以是 显式转换为不同类型的 prvalue "指针指向 类型 T2 的 Y 的成员",如果 T1 和 T2 都是函数类型或两者兼而有之 对象类型。[...].此转换的结果未指定, 除以下情况外:
(10.1) 将"指向成员函数的指针"类型的 prvalue 转换为 指向成员函数类型的不同指针并返回到其原始状态 键入生成指向成员值的原始指针。
(10.2) 将 "指针"类型的 prvalue 转换为 X 的数据成员 类型 T1"到类型"指向类型 T2 的 Y 的数据成员的指针"(其中 T2的对准要求不比T1严格)和 返回到其原始类型将生成指向成员值的原始指针。
对于reinterpret_cast
我们看到允许强制转换(如您所见,没有编译器错误。但是,结果未指定,除了上述 2 种情况,这意味着转换回原始值。它不适用于我们的情况,这意味着您的代码具有reinterpret_cast
具有未定义的行为。
此外
§5.5 指针到成员运算符 [expr.mptr.oper]
将 pm-expression 缩写为 .*cast-expression 为 E1.*E2,E1 称为 对象表达式 。如果 E1 的动态类型不包含 E2 引用的成员,行为未定义。
这证明instance.*bp
是有效的,因为bp
指向的对象必须存在于实例中。这意味着bp
的类型 .
- 使用取消引用的指针的多态性会产生意外的结果.为什么?
- Doees the 'this' 指针参与虚函数的多态行为
- 如何在基类指针向量的元素上应用重载的多态函数
- 具有智能指针的多态性
- 当目标指针不是基类的类型时,为什么允许dynamic_cast为多态类生成 null 指针?
- 如何模板化堆栈分配的多态指针数组到接口,包括派生类型的相应点?
- 如何使用静态多态性在 int 和指针类型之间进行转换?
- 无法初始化已知大小的矢量指针,该大小不会因多态性而更改
- 如何调用指针类型的方法(禁用多态性)?
- 当依赖关系和依赖关系都是多态时,在哪个继承级别存储依赖关系指针?
- 创建基类指针的向量并将派生类对象传递给它(多态性)
- 对于多态类型T,如何在没有类型T实例的情况下获得指向T的虚拟表的指针
- 如何避免指针超出范围(多态性)的C++分段错误
- C++ 被此代码与多态性、指针和对象切片混淆
- 在同时处理基类的多个指针时如何处理多态性?
- 如果基类指针无法访问派生类成员函数,那么多态性有什么方便的呢?
- 为什么在将多态行为与指向接口的指针一起使用时没有调用析构函数?
- 集合中的智能指针多态性
- c++智能指针多态
- 智能指针与哑指针:多态行为奇特