You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C++中构建合理类层次?Course与Lecture类设计咨询

问题解答

类关系判断:你的思路完全正确

Course和Lecture是组合关系——一门课程包含多场讲座,完全没必要用继承。继承是用来表达"is-a"的关系(比如MathLecture是一种Lecture),但讲座显然不是课程的一种,所以Course类持有Lecture集合的设计非常合理。

现有代码的几个问题

  • Lecture类定义在Course之后,编译器无法识别Course中的Lecture* m_lectures,需要先提前声明Lecture类;
  • 使用裸指针Lecture*管理数组极易引发内存泄漏,建议用std::vector<Lecture>这类标准容器替代,自动管理内存更省心;
  • 所有成员都设为私有,且没有对外的构造函数、访问方法,根本无法创建对象、添加讲座,更没法实现要求的三个功能;
  • 缺少数组/容器的长度信息,连遍历讲座都做不到。

改进后的完整代码实现

#include <string>
#include <vector>
#include <algorithm>
#include <optional>
#include <iostream>

// 提前声明Lecture类,解决编译器识别问题
class Lecture;

class Course
{
private:
    std::string m_name;
    std::string m_teacher_surname;
    std::vector<Lecture> m_lectures; // 用vector替代裸指针,动态管理讲座

public:
    // 构造函数:初始化课程名称和教师姓氏
    Course(std::string name, std::string teacher_surname)
        : m_name(std::move(name)), m_teacher_surname(std::move(teacher_surname)) {}

    // 添加讲座的方法
    void add_lecture(Lecture lecture)
    {
        m_lectures.push_back(std::move(lecture));
    }

    // 1. 找出学生最少的讲座(返回optional处理无讲座的边界情况)
    std::optional<const Lecture*> find_least_attended_lecture() const
    {
        if (m_lectures.empty())
            return std::nullopt;

        const auto& min_lecture = *std::min_element(m_lectures.begin(), m_lectures.end(),
            [](const Lecture& a, const Lecture& b) {
                return a.get_present_students() < b.get_present_students();
            });
        return &min_lecture;
    }

    // 2. 获取包含特定关键词的主题列表
    std::vector<std::string> get_topics_with_keyword(const std::string& keyword) const
    {
        std::vector<std::string> matched_topics;
        for (const auto& lecture : m_lectures)
        {
            const std::string& topic = lecture.get_topic();
            if (topic.find(keyword) != std::string::npos)
            {
                matched_topics.push_back(topic);
            }
        }
        return matched_topics;
    }

    // 3. 获取教师姓氏的最后一个字符
    char get_last_char_of_teacher_surname() const
    {
        if (m_teacher_surname.empty())
            return '\0'; // 处理空姓氏的异常情况
        return m_teacher_surname.back();
    }

    // 辅助打印课程信息,方便演示
    void print_course_info() const
    {
        std::cout << "课程名称: " << m_name << "\n";
        std::cout << "教师姓氏: " << m_teacher_surname << "\n";
        std::cout << "讲座总数: " << m_lectures.size() << "\n";
    }
};

class Lecture
{
private:
    std::string m_date;
    std::string m_topic;
    int m_present_students;

public:
    // 构造函数:初始化讲座的日期、主题、到场学生数
    Lecture(std::string date, std::string topic, int present_students)
        : m_date(std::move(date)), m_topic(std::move(topic)), m_present_students(present_students) {}

    // 私有成员的访问器方法(保证封装性的同时提供必要的访问接口)
    int get_present_students() const { return m_present_students; }
    const std::string& get_topic() const { return m_topic; }
    const std::string& get_date() const { return m_date; }
};

// 功能演示
int main()
{
    Course cpp_course("C++进阶编程", "Smith");
    cpp_course.add_lecture(Lecture("2024-05-01", "智能指针原理与实践", 35));
    cpp_course.add_lecture(Lecture("2024-05-08", "STL容器深度解析", 28));
    cpp_course.add_lecture(Lecture("2024-05-15", "Lambda表达式与算法应用", 32));

    cpp_course.print_course_info();

    // 查找学生最少的讲座
    if (auto least_lecture = cpp_course.find_least_attended_lecture())
    {
        std::cout << "\n学生最少的讲座: " << (*least_lecture)->get_topic() 
                  << ",到场人数: " << (*least_lecture)->get_present_students() << "\n";
    }

    // 查找含"容器"关键词的主题
    auto matched_topics = cpp_course.get_topics_with_keyword("容器");
    std::cout << "\n含'容器'的主题列表:\n";
    for (const auto& topic : matched_topics)
    {
        std::cout << "- " << topic << "\n";
    }

    // 获取教师姓氏最后一个字符
    std::cout << "\n教师姓氏最后一个字符: " << cpp_course.get_last_char_of_teacher_surname() << "\n";

    return 0;
}

代码说明

  • 用std::vector<Lecture>替代裸指针,既避免内存泄漏,又支持动态添加讲座;
  • 为两个类添加了构造函数和必要的访问器,在保证封装性的前提下,提供了操作接口;
  • 完整实现了要求的三个功能:
    1. 用std::min_element结合Lambda表达式快速找到学生最少的讲座,用std::optional处理无讲座的边界情况;
    2. 遍历所有讲座,通过std::string::find匹配关键词,收集符合条件的主题;
    3. 用std::string::back()直接获取姓氏最后一个字符,同时处理了空字符串的异常情况;
  • 附带main函数演示了所有功能的使用方式。

内容的提问来源于stack exchange,提问作者Anakin Codewalker

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 10:40:19