C++将指向派生类的基类指针转为同基另一派生类指针为何不崩溃
问题相关代码
#include <iostream> class Entity { private: int entityInt_; public: Entity() : entityInt_(0) {} virtual void print() const { std::cout << "This is Entity class\n"; } }; class Player : public Entity { private: int playerInt_; public: Player() : playerInt_(0) {} void print() const { std::cout << "This is Player class\n"; } }; class Enemy : public Entity { private: int enemyInt_; double enemyFloat_; public: Enemy() : enemyInt_(0), enemyFloat_(0.0) {} void exclusiveEnemy() const { std::cout << "This is an exclusive method of Enemy class\n"; } void print() const { std::cout << "This is Enemy class\n"; } }; int main(int argc, const char* argv[]) { Entity* actuallyPlayer = new Player(); Enemy* enemy = static_cast<Enemy*>(actuallyPlayer); enemy->print(); enemy->exclusiveEnemy(); }
原因解释
你给出的代码本质属于C++未定义行为(Undefined Behavior),看起来运行正常只是特定编译、运行环境下的巧合,不代表代码逻辑合法,换编译选项、编译器或者运行环境随时可能崩溃、输出异常结果。
没有崩溃的具体原因可以分为三点:
static_cast<Enemy*>(actuallyPlayer)这个向下转型本身就不合法:static_cast做类指针向下转型时不会做运行时类型检查,编译器默认你保证指针指向的内存确实是目标类型Enemy的实例,你现在实际指向的是Player实例,这一步就已经触发未定义行为。- 调用
enemy->exclusiveEnemy()未崩溃的原因:这个方法是非虚成员函数,且实现中没有访问任何Enemy类的非静态成员变量。非虚成员函数本质是带隐式this参数的普通全局函数,只要调用过程中没有读写this指向的内存数据,哪怕this指针指向非法内存,也不会触发访问异常,这里函数只是输出固定字符串,完全没用到成员变量,所以运行正常。 - 调用
enemy->print()输出This is Enemy class的原因:print是虚函数,正常来说应该根据对象实际类型的虚表调用对应实现,但你的代码属于未定义行为,编译器有权做任意处理。大概率是你的编译器做了优化,认为通过Enemy*类型指针调用print可以跳过虚表查询,直接静态绑定到Enemy::print实现,所以输出了Enemy的打印内容,这也是未定义行为的一种表现。
如果需要安全做向下转型,应该使用dynamic_cast,会在转型失败时返回空指针(针对指针类型)或者抛出异常(针对引用类型),避免出现这类非法访问问题。
内容的提问来源于stack exchange,提问作者David Pérez Sánchez
相关产品推荐
相关产品推荐

