C++扩展std::string等内置类时父类原生方法失效如何解决?
问题原因分析
你的猜测是正确的,问题确实出在构造函数的实现上,本质是继承了std::string后没有正确初始化父类对象,仅给子类新增的独立成员s赋值,父类的实际存储内容始终是空串:
- 你定义的str类同时持有两个string存储:一个是继承自父类std::string的内置存储,另一个是你自定义的子类成员
s - 你在构造函数中仅给子类自定义的
s赋值,继承得到的父类string部分走的是无参默认构造,内容为空 - 调用
s.size()时实际调用的是父类std::string的size()方法,读取的是父类空串的长度,自然返回0
解决方案
方案1:保留继承写法,正确初始化父类
删掉子类多余的自定义成员s,直接复用继承自父类的存储,通过构造函数初始化列表调用父类的构造函数完成赋值即可,示例代码如下:
#include <iostream> #include <string> using namespace std; class str : public string { public: // 初始化列表调用父类std::string的构造函数 str(const string& s1) : string(s1) {} // 可在此处添加你的自定义方法,示例为转大写 void to_upper() { for (auto& c : *this) c = toupper(c); } }; int main() { str s("hello world"); cout << s.size() << endl; // 正确输出11 s.to_upper(); cout << s << endl; // 输出HELLO WORLD return 0; }
注意:std::string的析构函数不是虚函数,如果你后续存在用父类指针指向子类对象、再通过父类指针销毁对象的用法,会出现内存泄漏风险,该方案仅适合确定不会出现这类用法的场景。
方案2:改用组合实现(更安全)
如果要规避虚析构带来的风险,更推荐用组合而非继承的方式实现自定义字符串类,按需封装原生方法和自定义方法即可:
#include <iostream> #include <string> using namespace std; class str { private: string s; // 用组合的方式持有std::string成员 public: str(const string& s1) : s(s1) {} // 封装需要用到的std::string原生方法 size_t size() const { return s.size(); } // 重载输出运算符 friend ostream& operator<<(ostream& os, const str& obj) { os << obj.s; return os; } // 自定义方法 void to_upper() { for (auto& c : s) c = toupper(c); } }; int main() { str s("hello world"); cout << s.size() << endl; // 输出11 s.to_upper(); cout << s << endl; // 输出HELLO WORLD return 0; }
内容的提问来源于stack exchange,提问作者Kaushik Kalesh
相关产品推荐
相关产品推荐

