0

这如果是为了我的家庭作业。

我有一个名为的类Student,它需要 3 个参数(id, name, class),我想将每个学生存储在一个名为的数组中Roster(它只能有 7 个学生)。

用户将提供输入以添加或删除学生。因此,我必须通过创建或删除学生来管理数组。因此,如果用户指定学生 ID,我必须将他删除为数组。

我尝试使用固定数组,但我正在努力使其工作。有没有更好的方法来实现这一点?

我不能使用一个vector或任何 STL 容器。

学生.h

#ifndef STUDENT_H
#define STUDENT_H
#include <iostream>
#include <string>

static const int SIZE = 7;

class Student {  
        private:
        int student_id;
        std::string name;
        std::string classification;

        public:
        Student(int, std::string, std::string);     // constructor; initialize the list to be empty
        ~Student();
        void print();

    };

#endif

学生.cpp

#include <iostream>
#include <string>

#include "student.h"

#define PROMPT "class> "
using namespace std;

Student::Student(int a, string b, string c){
    student_id = a;
    name = b;
    classification = c;
}

Student::~Student(){
    //delete Student
}

void Student::print(){
    cout<<"Enrolled:"<<endl;
    cout<<student_id<<"-"<<name<<"-"<<classification<<endl;
}

主文件

#include <iostream>
#include <string>
//#include <sstream>
#include "student.h"

#define PROMPT "class> "
using namespace std;


//**** Implement Error Handling ****\\

enum errorType {
    UNKNOWN_ERROR,
    INPUT_ERROR,
    HANDLER,
    NUM_ERRORS
};

// error messages

string errorMessage[NUM_ERRORS] = {
    "Unknown Error\n",
    "Input Error\n",
};

// error handler

void handleError(errorType err) {
    if(err > 0 && err < NUM_ERRORS)
        cout<< "Error: "<< errorMessage[err];
    else cout<< "Error: "<< errorMessage[UNKNOWN_ERROR];
}

//**** END Error Handling ****\\



void enroll(Student newStudent){
        cout<<"test";
        Student roster[SIZE];
     for(int i=0;i<SIZE;i++){
        newStudent->roster[i];
     }
}

void handleInput() {
    int id; string n, c;

    cin>>id>>n>>c; 
    Student newStudent(id,n,c);
    newStudent.print(); 
    enroll(newStudent);
    //cout<<"hello3"<<endl;
    return;
}


int main() {
    //Student newStudent;   /* <-- why doesn't this work?!*/
    string input = "";
    bool finished = false;

    cout<<PROMPT; // prompt the user
    while(!finished) {
        if(input!="") cout<<PROMPT;
        cin>>input;
        if(input=="enroll") {
            cout<<PROMPT<<"Enroll student:"<<endl;
            handleInput();
        }
        else if(input=="drop") {
            cout<<PROMPT<<"Enter ID:"<<endl;
        }
        else if(input=="roster") {
            cout<<"This will print formatted list of students"<<endl;
        }
        else if(input=="quit") {
            finished=true;
        }
        else handleError(errorType(1));
    }
}
4

4 回答 4

2

由于这是一项家庭作业,我想指出你犯的一些错误,因为首先了解你在做什么很重要。

您绝不能巧合地编程,而是试图准确地理解正在发生的事情。通过这样做,您将变得越来越好,并且答案应该到位。

你做了什么

因此,根据您的描述,数组是固定的。因此,像您一样使用常量 (SIZE) 是一个好主意。

但是,正如我们在下面看到的,在函数中声明了一个大小为 SIZE 的数组。通过这样做,您的数组就像一个临时变量,因为它的范围在函数内部。每次调用该函数时,都会再次声明该数组,然后在退出时删除该数组。所以应该在外面声明。

void enroll(Student newStudent)
{
     cout<<"test";
     Student roster[SIZE]; // Here 'roster' will be available only inside the function.
     
     for(int i=0;i<SIZE;i++)
     {
        newStudent->roster[i]; // Here there is few mistakes see my explanation below*
     }
}

如果我们看这部分:

newStudent->roster[i];

首先,箭头'->' 与指针一起使用。点“。” 与对象一起使用。在这两种情况下,它都做同样的事情,访问 Student 的公共成员。

自从你通过

void enroll(Student newStudent)

你应该使用 ' ' 反而。

newStudent.SomeOfYourMembers;

如果参数是指向学生的指针

void enroll(Student *newStudent)

然后,您必须像以前一样使用箭头“->”。

回到原来的说法:

newStudent->roster[i];

这意味着,您希望访问学生对象 (newStudent) 内位置“i”处的“名册”数组。正如您在代码中看到的那样, roster 没有在 Student 内部声明(并且不应该因为您想要一个 Student 数组),所以这是行不通的。

指导方针

正如我所提到的,您的数组应该在函数之外,因此在更高的范围内。

然后,如果你需要一个学生数组,基本上,'roster[i]' 会让你访问学生'i'。因此,如果你想打印学生,你会做这样的事情:

roster[i].print();

这将是有效的,因为 'print()' 被定义为公共的。

为了将学生存储在数组中,您可以执行以下操作:

roster[i] = new Student(0 /* id*/, "name", "classification");

但是不要忘记,每次使用 new 的时候,都要用 delete 来平衡它。如果您在循环中创建这样的学生,则必须以相同的方式清理它们:

for(int i = 0; i < SIZE; ++i)
{
    delete roster[i];
}

祝你好运!

如果有什么我可以澄清的,请不要犹豫。我希望这有帮助!

编辑:回复您的第一条评论。

关于名册排列

不,创建班级名册不是强制性的,您可以在 main.cpp 中声明名册。

关键概念是通过定义

Student roster[SIZE]; 

该数组将包含 Student 类型的对象。

roster[i].print() 的意思是您正在打印该数组的一个学生,实际上是位于“i”位置的那个。

关于 print() 函数

面向对象语言的强大之处在于,每个对象都将具有相同的 print() 函数。因此,您不需要将数组转换为字符串。

但是,如果您想要打印出(或返回)字符串,您可以在 print() 函数中编写代码来完成这项工作。

这样做的好处是,如果您需要进一步以某种方式更改数组,您的 print() 函数将始终有效。

关于删除

当您在包含对象的数组上执行类似操作时:

delete roster[i];

它将删除位置“i”处的对象。因此,将调用该学生“i”的析构函数。如果您的对象 Student 包含其他对象,则必须在析构函数中删除它们。

进一步通知

由于 ID 是您存储到字符串中的输入,因此您必须将 ID 转换为与 student_id 相同的类型,即 int。然后,您始终可以为每个学生编写一个循环并检查他们的 ID 以删除正确的 ID。

关于容器,固定数组可能不是完成这项工作的最佳选择。您可能想查看LinkedList 概念

于 2012-06-23T02:47:10.610 回答
1

成为成员函数没有多大意义enroll,所以我将名册包装到一个类中以自动清理我的指针。

#include <cstddef>

struct Student {};

class Roster
{
private:
  static const size_t size = 7; 
  // non-copyable
  Roster(const Roster&);
  Roster& operator=(const Roster&);
public:
  Roster() {
    for(unsigned i = 0; i < size; ++i) {
      roster_[i] = NULL;
    }
  }

  ~Roster() {
    for(unsigned i = 0; i < size; ++i) {
      delete roster_[i];
    }
  }

  // enroll by copy
  bool enroll(const Student& s) {
    for(unsigned i = 0; i < size; ++i) {
      if(roster_[i] == NULL) {
        roster_[i] = new Student(s);
        return true;
      }
    }
    // out of space
    return false;
  }

  // enroll by taking ownership
  bool enroll(Student* s) {
    for(unsigned i = 0; i < size; ++i) {
      if(roster_[i] == NULL) {
        roster_[i] = s;
        return true;
      }
    }
    // out of space
    return false;
  }

private:
  // data
  Student* roster_[size];
};


int main()
{
  Roster r;
  Student s;
  r.enroll(s);
  Student* sp = new Student();
  r.enroll(sp);
  return 0;
}
于 2012-06-23T02:00:00.637 回答
0

那这个呢?

Student * roster[2];
roster[0] = new Student(5,"first","2A");
roster[1] = new Student(2,"Second","5B");

附言:

Enroll 和 Size 不应该是学生班级的成员。理想情况下,打印应该被外部化,而应该添加一个 ToString 函数。

您应该改用内联构造函数初始化:

Student(int a,string b,string c):id(a),name(b),class(c){}
于 2012-06-23T02:03:50.230 回答
0

您已将关键字class用作字符串类型的变量名。你不应该那样做。它甚至可以这样编译吗?

enroll应该有两个参数:void enroll( Student enrollee, Student Roster[]). 您可能应该更改 to 的名称,Roster因为roster它不是一个类,并且通常类名大写。

如果您的数组只有 7 个学生,那么您可以使用一些哨兵值将当前学生标记为无效学生。也许id将要-1标记这一点。这基本上意味着您需要一些方法来跟踪您仍然可以使用阵列中的哪些点。如果您不这样做,那么声明一个学生数组将为您提供一个带有垃圾成员变量的学生数组。您将无法分辨哪些学生是真实的学生,哪些只是新入学时的占位符。我将创建一个默认构造函数Student并初始化其成员变量,如下所示:

id=-1;
name="";
name_of_class="";

我更改了你的名字string class以避免混淆。

毕竟,注册看起来像这样:

void Student::enroll( Student enrolee, Student roster[]){

    //search through roster to check for the first student with an
    //id of -1
    //if there are no students with id of -1, produce an error message
    //that the class is full

    //overwrite the student with id of -1  with the id, name, and
    //name_of_class of enrollee


}

虽然我不确定到底string class是为了什么。它是否存储学生所在的班级?他们像大一、大二一样在校学习吗?

但是,如果您想使用名册的动态分配,那就另当别论了,但是您说它永远只有七名学生。

于 2012-06-23T02:33:53.707 回答