以下代码中的rpd
会导致未定义的行为吗?如果是这样,是否可以以类型安全的方式定义class Base
{
public:
virtual ~Base() = default;
};
class Derived : public Base { };
int main(void)
{
Derived d;
Base* pb = &d;
Base*& rpb = pb;
Derived*& rpd = reinterpret_cast<Derived*&>(rpb);
return 0;
}
?
++
与我之前的recent question相关的排序。背后的背景;我正在尝试一个适配器类,它应该允许包含协变指针类型的向量本身用作协变类型。
答案 0 :(得分:3)
强制转换本身没有UB(参见[expr.reinterpret.cast]),但通过重新解释的引用(rpb
)访问引用的指针(rpd
)会:
[basic.lval](标准草案)
如果程序试图通过以下类型之一以外的glvalue访问对象的存储值,则行为未定义: 56
56)此列表的目的是指定对象可能有或没有别名的情况。
- (8.1) 对象的动态类型,
不适用,动态类型是Base*
的静态类型,而不是glvalue类型的Derived*
。
- (8.2) 对象的动态类型的cv限定版本,
没有cv资格,且类型仍然不匹配。
- (8.3) 类似于对象的动态类型的类型
不适用。这是关于cv-qualifier de-composition,请参阅[conv.qual](对不起,段落中的许多下标很难输入html,并且是保持文本可读的必要条件。)
- (8.4) 与对象的动态类型对应的有符号或无符号类型的类型
仅与整数类型相关。
- (8.5) 与对象的动态类型的cv限定版本对应的有符号或无符号类型的类型,
同上。
- (8.6) 聚合或联合类型,包括其元素或非静态数据成员中的上述类型之一(包括递归地,子聚合或包含联合的元素或非静态数据成员),
Derived*
既不是聚合也不是联盟。
- (8.7) 一种类型,它是对象动态类型的(可能是cv限定的)基类类型,
Derived*
不是Base*
的基础。
- (8.8) char,unsigned char或std :: byte类型。
Derived*
不是那些。
由于没有例外情况适用,因此Base*
类型的glvalue访问Derived*
的行为未定义。
我正在尝试一个适配器类,它应该允许包含协变指针类型的向量本身用作协变类型。
您的实验将无法维护基本的面向对象原则。
基本引用与派生协变,因为您无法通过基本引用对派生对象本身执行任何操作。
基类型的容器不能与派生容器协变,因为你可以使用一个容器(通过“引用”容器派生)基于你无法对派生容器做的事情做一些事情:添加对象其他派生类型。
虽然,如果容器是不可变的......它可能在概念上有效。实际上用C ++实现它是另一回事。