我写了一个不安全static_cast
的小例子:
#include <iostream>
class A
{
public:
virtual int getA(){ return 1; }
};
class B : public A
{
public:
virtual int getA() { return 2; }
int getB() { return 3; }
};
int main()
{
A a;
B b;
B* b1 = static_cast<B*>(&a);
std::cout << "b.getA(): " << b.getA() << std::endl;
std::cout << "b.getB(): " << b.getB() << std::endl;
std::cout << "b1->getA(): " << b1->getA() << std::endl;
std::cout << "b1->getB(): " << b1->getB() << std::endl;
}
输出:
b.getA(): 2
b.getB(): 3
b1->getA(): 1
b1->getB(): 3
我认为它不安全,因为我在创建B
时从未运行b1
构造函数,尽管将其作为B
对象访问。显然,输出的差异表明b1
没有指向B
对象,而是指向A
对象,正如预期的那样。
这方面的其他方面是不安全的。它是否涉及未定义的行为甚至像这样执行static_cast
?否则,访问getA
或getB
方法可能是未定义的行为吗?
还有别的吗? (我不关心在这个例子中我不关心的遗漏的虚拟析构函数)
cpp.sh上可用的代码:http://cpp.sh/7sxtz
答案 0 :(得分:1)
执行print
后访问*b1
的值是未定义的行为:
static_cast
如果程序试图通过除了其中一个之外的glvalue访问对象的存储值 以下类型行为未定义- 对象的动态类型,
- 对象的动态类型的cv限定版本,
- 与对象的动态类型相似的类型(如4.4中所定义)
- 与对象的动态类型对应的有符号或无符号类型
- 对应于动态类型的cv限定版本的有符号或无符号类型 对象,
- 聚合或联合类型,包括其元素中的上述类型之一或非 静态数据成员(包括递归地,子集合的元素或非静态数据成员) 或包含联盟),
- 一种类型,是对象动态类型的(可能是cv限定的)基类类型,
- char或unsigned char类型。
答案 1 :(得分:1)
static_cast<B *>(&a)
导致未定义的行为。
C ++ 14 [expr.static.cast] / 11:
[...]如果类型为“指向cv1
B
的指针”的prvalue指向实际上是B
类型对象的子对象的D
,则生成指针指向D
类型的封闭对象。否则,行为未定义。