C++ new动态创建Student对象数组语法及带参构造实现方法
1. Student *s = new Student[n]; 语句的作用与执行逻辑
这行代码的作用是在堆内存上动态创建长度为n的Student类型对象数组,执行流程分三步:
- 申请连续堆内存:计算存储n个Student对象所需的总内存大小(即
n * sizeof(Student)),向系统申请对应大小的连续内存块。 - 批量构造对象:内存申请成功后,对数组内的n个元素逐个调用Student类的默认无参构造函数完成初始化。你贴的示例代码里Student类没有自定义构造函数,用的是编译器自动生成的默认无参构造,不会给scores数组赋初始值,内存里会残留随机脏值,但因为后续马上调用
input()方法覆盖了scores的值,所以不影响运行结果。 - 返回地址赋值:构造完成后返回数组首元素的内存地址(类型为
Student*),赋值给指针变量s。后续可以通过s[i]的下标语法直接访问第i个Student对象,和普通栈数组的访问方式一致。
补充说明:你通过cppinsights看到的展开结果是
new Student [](),这是值初始化的写法,和new Student[n]的差异是:对于你写的这种没有自定义构造的简单类,值初始化会把int类型的scores成员全部置0,而默认的new Student[n]不会做这步初始化。另外这种new出来的堆数组必须配套用delete[] s释放内存,否则会造成内存泄漏,刷题时因为程序运行完就退出,系统会自动回收内存,所以不写delete也不会触发报错。
2. 带参数化构造函数时的动态数组创建方法,及任意学生成绩对比实现
如果Student类自定义了接收姓名/ID的参数化构造函数,编译器就不会再自动生成默认无参构造,此时直接写new Student[n]会编译失败——因为原生new数组语法默认需要无参构造来批量初始化所有元素。实际开发中常用两种方案解决:
方案1:保留无参构造,补充成员赋值方法
显式给Student类加一个无参构造函数,同时增加set_basic_info()、input_scores()这类成员方法。动态创建n个默认构造的Student对象后,循环读入每个学生的姓名、ID、成绩信息,调用对应方法给对象赋值即可,这种写法和原题的代码逻辑兼容性最高。
方案2:用标准库vector存储,逐个构造对象(推荐)
原生new数组不支持给每个对象传入不同的构造参数,灵活性很差,绝大多数场景下直接用std::vector<Student>代替原生数组即可,不需要提前批量构造对象,每读入一个学生的完整信息,就调用参数化构造生成单个对象存入vector,完全不需要依赖无参构造。
参考实现片段:
#include <vector> #include <string> using namespace std; class Student { private: string name; int stu_id; int scores[5]; public: // 仅定义参数化构造,无默认无参构造 Student(string input_name, int input_id, int input_scores[5]) { name = input_name; stu_id = input_id; for (int i = 0; i < 5; i++) { scores[i] = input_scores[i]; } } int get_total_score() { int sum = 0; for (int s : scores) sum += s; return sum; } string get_name() { return name; } int get_id() { return stu_id; } }; int main() { int n; cin >> n; vector<Student> stu_list; // 逐个读入学生信息,构造对象存入vector for (int i = 0; i < n; i++) { string name; int id; int scores[5]; cin >> name >> id; for (int j = 0; j < 5; j++) { cin >> scores[j]; } stu_list.emplace_back(name, id, scores); // 直接调用参数化构造,无需无参构造 } // 实现任意学生成绩对比:比如输入要查询的学生ID,统计成绩高于他的人数 int query_id; cin >> query_id; int target_score = 0; for (auto& stu : stu_list) { if (stu.get_id() == query_id) { // 也可以换成按姓名匹配等自定义逻辑 target_score = stu.get_total_score(); break; } } int higher_count = 0; for (auto& stu : stu_list) { if (stu.get_total_score() > target_score) { higher_count++; } } cout << higher_count << endl; return 0; }
注意:不要尝试用
new Student[n](参数)的写法给数组传构造参数,这种语法只支持给所有对象传入完全相同的参数,无法实现每个学生对应不同姓名/ID的需求,没有实用价值。用vector的方案还会自动管理内存,不需要手动调用delete,能避免绝大多数内存泄漏问题。
内容的提问来源于stack exchange,提问作者yusah

