C++中基类的动态类型转换问题(兼容C++14)
问题分析与解决方案
原代码存在三个核心问题,导致无法实现预期的多态输出:
- 对象切片:函数
s返回A类型对象,当返回子类B/C时,会被切割成基类A的实例,丢失子类特有的信息和行为。 - 无多态支持:基类
A没有定义任何虚函数,无法通过基类指针/引用触发子类的operator<<重载。 - 非法解引用:
s返回的是A对象而非指针,*(s(0))属于语法错误,编译无法通过。
以下是兼容C++14标准的修改方案:
修改后的完整代码
#include <iostream> #include <memory> #include <string> using namespace std; class A { public: // 虚析构:确保子类对象通过基类指针销毁时能正确调用子类析构 virtual ~A() = default; // 纯虚打印函数:定义多态接口 virtual void print(ostream& out) const = 0; }; // 全局operator<<,调用基类的虚print函数实现多态输出 ostream& operator<<(ostream& out, const A& obj) { obj.print(out); return out; } class B : public A { public: explicit B(string s) {} // 实现基类的纯虚print函数 void print(ostream& out) const override { out << "b"; } }; class C : public A { public: explicit C(int i) {} // 实现基类的纯虚print函数 void print(ostream& out) const override { out << "c"; } }; // 返回unique_ptr<A>,避免对象切片,同时自动管理内存(C++14支持) unique_ptr<A> s(int i) { if (i == 0) { return make_unique<B>("hello world"); } else { return make_unique<C>(12); } } int main() { // 解引用unique_ptr获取基类引用,触发多态输出 cout << *(s(0)) << endl; // 输出"b" cout << *(s(1)) << endl; // 输出"c" return 0; }
修改细节说明
- 基类添加虚函数:为
A添加虚析构和纯虚print函数,开启多态支持。虚析构是必须的,否则通过基类指针销毁子类对象会导致未定义行为。 - 替换返回值类型:将
s的返回值从A改为unique_ptr<A>,避免对象切片,同时利用智能指针自动管理内存,无需手动释放(C++14的make_unique是标准库函数,安全高效)。 - 调整输出逻辑:将子类的
friend operator<<改为实现基类的print虚函数,全局operator<<统一调用基类的print,确保通过基类引用能触发子类的输出逻辑。
内容的提问来源于stack exchange,提问作者Niles
相关产品推荐
相关产品推荐

