C++继承场景下基类set调用派生类get的OOP实现优化问题
问题核心缺陷
你当前的实现存在两个核心的OOP设计问题:
- 对象切片:
SortedList直接存储student基类对象,派生类的特有成员(如省份、国家、托福成绩)存入时会被直接截断,你现在手动把派生类属性同步到基类冗余字段T的写法属于临时妥协,完全没有利用继承的优势,后续要扩展派生类特有功能时完全无法实现。 - 无多态支持:基类的
getT/setT没有定义为虚函数,无法触发多态调用,手动同步字段的写法极易出错,也不符合开闭原则。
符合OOP规范的改造方案
核心思路是用基类智能指针存储多态实例,避免对象切片,同时用虚函数实现多态调用:
- 改造
student基类为抽象基类,添加虚析构函数,将getT/setT定义为纯虚函数,删除冗余的T字段。 - 派生类继承基类后,override实现对应的虚函数,保留自身特有属性。
SortedList改为存储std::unique_ptr<student>(或std::shared_ptr<student>),而非基类对象,从根源上避免对象切片。- 读取数据时直接创建派生类实例,封装为智能指针后存入链表,无需手动同步基类字段。
核心代码示例
改造后的基类
#include <string> #include <memory> class student { template<class T> friend class SortedList; template<class T> friend class Node; public: student() = default; student(int new_Id, std::string new_FirstName, std::string new_LastName, float new_Cgpa, int new_ResearchScore) : FirstName(std::move(new_FirstName)), LastName(std::move(new_LastName)), cgpa(new_Cgpa), researchscore(new_ResearchScore) {} // 必须添加虚析构函数,避免派生类对象销毁时内存泄漏 virtual ~student() = default; std::string getFirstName() const { return FirstName; } void setFirstName(std::string new_FirstName) { FirstName = std::move(new_FirstName); } std::string getLastName() const { return LastName; } void setLastName(std::string new_LastName) { LastName = std::move(new_LastName); } float getcgpa() const { return cgpa; } void setCgpa(float new_Cgpa) { cgpa = new_Cgpa; } int getresearchscore() const { return researchscore; } void setresearchscore(int new_ResearchScore) { researchscore = new_ResearchScore; } // 纯虚函数,强制派生类实现 virtual std::string getT() const = 0; virtual void setT(std::string t) = 0; // 扩展特有属性时可加其他虚函数,比如virtual int getToeflScore() const { return 0; } private: std::string FirstName; std::string LastName; float cgpa; int researchscore; // 删除冗余的T字段 };
派生类示例(国内学生)
class domesticstudent : public student { public: using student::student; // 继承基类构造函数 domesticstudent(int the_ID, std::string The_FN, std::string The_LN, float The_cgpa, int the_RS, std::string newProvince) : student(the_ID, The_FN, The_LN, The_cgpa, the_RS), province(std::move(newProvince)) {} std::string getT() const override { return province; } void setT(std::string newProvince) override { province = std::move(newProvince); } private: std::string province; };
链表与主逻辑改造
// 链表声明改为存储基类智能指针 SortedList<std::unique_ptr<student>> list_domestic; SortedList<std::unique_ptr<student>> list_international; // 读取国内学生逻辑示例 auto dom_stu = std::make_unique<domesticstudent>(id, firstname, lastname, cgpa, researchscore, province); list_domestic.listset(std::move(dom_stu)); // 读取国际学生逻辑示例 auto inter_stu = std::make_unique<internationalStudent>(id, firstname, lastname, cgpa, researchscore, country, toefl_score); list_international.listset(std::move(inter_stu)); // 两个链表元素类型完全一致,可直接合并,调用getT时会自动触发多态返回对应属性
改造优势
- 完全避免对象切片,派生类所有特有属性都可以完整保留,后续扩展功能不需要修改基类逻辑,符合开闭原则。
- 基于多态的调用不需要手动同步字段,代码简洁不易出错。
- 智能指针自动管理对象生命周期,无需手动释放内存,避免内存泄漏。
- 两个链表元素类型统一,合并时不需要任何额外转换,完全满足你的需求。
内容的提问来源于stack exchange,提问作者Colton F
相关产品推荐
相关产品推荐

