为何引用未创建的派生类指针合法且不属于未定义行为?
C++中基类指针转未构造派生类指针的合法性与未定义行为分析
先看示例代码:
#include <iostream> struct A{ int a; void foo() { std::cout << "A = " << a << std::endl; } }; struct B : public A{ int b; void foo() { std::cout << "B = " << b << std::endl; } }; int main() { A *a = new A(); B *b = static_cast<B*>(a); a->foo(); // 输出 A = 0 b->foo(); // 输出 B = 0 b->b = 333; b->foo(); // 输出 B = 333 a->foo(); // 输出 A = 0 }
核心问题拆解
指针转换操作本身的合法性
static_cast<B*>(a)这个转换在public继承场景下是C++标准允许的语法,但这只是编译期允许的转换——得到的指针并不指向真正的B类型对象,因为我们只构造了A的实例,内存中根本没有B独有的b成员对应的空间。后续操作的未定义行为
- 调用
b->foo():因为foo是非虚函数,调用是编译期绑定的,编译器直接生成调用B::foo的代码。但B::foo中访问的b成员,对应的是A对象内存之后的未知区域,第一次读取到0是随机的未初始化内存值,而b->b = 333则是越界修改不属于当前对象的内存,这两种操作都属于明确的未定义行为。 - 你看到的输出"正常"只是巧合,换不同编译器、优化级别或运行环境,可能出现崩溃、乱码、程序异常终止等任意结果。
- 结论
基类指针强转为派生类指针的操作本身不是未定义行为,但通过这个指针访问派生类独有的成员、或是在虚函数机制下调用成员函数,都属于未定义行为。这种写法完全依赖不可靠的内存巧合,绝对不能出现在生产代码中。
内容的提问来源于stack exchange,提问作者zizeca
相关产品推荐
相关产品推荐

