C++工厂函数问题排查与修正:如何让输出变为1 2 3?
问题分析与修复方案
先直接拆解你的代码里导致输出全为0的核心问题,再给出完整的修复方案:
1. 致命的对象切片问题
你在工厂函数里写的make_unique<Base>(A())这类代码,本质是用派生类对象去构造基类对象,这会触发C++的「对象切片」——派生类特有的数据和行为会被直接切掉,最终你拿到的永远是一个纯Base类型的对象,而非你期望的A/B/C派生类对象。这是所有输出都是0的核心原因。
2. Switch分支缺少break导致逻辑贯穿
你的switch语句里每个case后都没加break,比如当传入_A时,代码会依次执行_A、_B、_C的分支,最后都会走到base = make_unique<Base>(C())。不过因为已经有切片问题,这个bug暂时没影响最终输出,但必须修复。
3. 派生类未正确重写虚函数
基类的getType()是虚函数,但你的A/B/C类并没有重写它,只是各自定义了一个私有type成员。这意味着哪怕你拿到了真正的派生类对象,调用getType()还是会执行基类的版本,返回基类的_Base值。
修复后的完整代码
#include <iostream> #include <memory> using namespace std; enum Type { _Base, _A, _B, _C }; class Base{ protected: Type type = _Base; public: virtual Type getType(){ return type; } // 基类必须加虚析构,避免通过基类指针删除派生类时内存泄漏 virtual ~Base() = default; }; class A : public Base{ public: A() { type = _A; } // 用override明确标记重写,让编译器帮你检查是否符合重写规则 Type getType() override { return type; } }; class B : public Base{ public: B() { type = _B; } Type getType() override { return type; } }; class C : public Base{ public: C() { type = _C; } Type getType() override { return type; } }; shared_ptr<Base> letterFactory(Type which){ switch (which){ case _A: return make_shared<A>(); case _B: return make_shared<B>(); case _C: return make_shared<C>(); default: return make_shared<Base>(); } } int main(){ shared_ptr<Base> instanceOfA = letterFactory(_A); cout << instanceOfA->getType() << endl; // 输出1 shared_ptr<Base> instanceOfB = letterFactory(_B); cout << instanceOfB->getType() << endl; // 输出2 shared_ptr<Base> instanceOfC = letterFactory(_C); cout << instanceOfC->getType() << endl; // 输出3 return 0; };
关键修改说明
- 解决对象切片:直接创建派生类的智能指针(
make_shared<A>()),再返回给shared_ptr<Base>,利用C++多态特性,此时指针指向的是真正的派生类对象,不会被切片。 - 修复分支逻辑:每个case直接返回对应智能指针,既避免了break的问题,也让代码更简洁。
- 正确实现多态:
- 把基类
type改为protected,让派生类可以修改; - 派生类用
override标记重写getType(),确保符合虚函数重写规则; - 给基类添加虚析构,避免内存泄漏。
- 把基类
- 简化冗余代码:去掉了没必要的
using Base::Base;,直接在派生类构造函数里设置type值。
这样修改后,程序就能输出1 2 3了。
内容的提问来源于stack exchange,提问作者CiaranWelsh
相关产品推荐
相关产品推荐

