C++中栈分配变量的虚方法为何未按预期工作?
为什么栈分配对象与指针的多态行为不同?
先看你定义的类:
class Entity { public: virtual std::string getName() { return "Entity"; } }; class Player : public Entity { private: std::string name_; public: Player(const std::string& name): name_(name) {} std::string getName() { return name_; } };
栈分配代码的问题:对象切片
运行这段栈分配代码时:
void print(const std::string& msg) { std::cout << msg << std::endl; } int main () { Player player("hello"); print(player.getName()); Entity e = player; print(e.getName()); }
实际输出是:
hello Entity
问题出在Entity e = player;这一行——这里发生了对象切片:
Player作为派生类,内存布局包含基类Entity的部分,加上自己的成员name_。- 当把
Player对象赋值给基类Entity的栈对象时,只会复制基类部分的数据,派生类特有的name_会被丢弃,最终e是一个独立的Entity对象,和原来的Player无关。 - 此时调用
e.getName(),因为e是Entity类型的实例,即便基类函数是虚函数,也不会触发多态,直接执行基类的getName方法。
指针代码符合预期的原因
使用指针的代码:
int main () { Player* player = new Player("hello"); std::cout << player->getName() << std::endl; Entity* e = player; std::cout << e->getName() << std::endl; return 0; }
输出符合预期:
hello hello
原因是:
- 基类指针
e并没有复制对象,只是指向了Player对象的内存地址,不存在切片问题。 - 因为
getName是虚函数,C++会通过对象的虚函数表(vtable),找到实际指向的Player类的getName方法,从而实现多态调用。
栈对象实现多态的正确写法
如果想在栈上实现多态,不要用值赋值,改用引用:
int main () { Player player("hello"); print(player.getName()); Entity& e = player; // 使用引用绑定到Player对象 print(e.getName()); }
引用不会复制对象,只是作为原对象的别名,因此不会发生切片,调用e.getName()时会触发多态,返回"hello"。
内容的提问来源于stack exchange,提问作者Shishir Jessu
相关产品推荐
相关产品推荐

