如何管理固定数组中的对象?

时间:2012-06-23 01:54:46

标签: c++ arrays

这是我的作业。

我有一个名为Student的课程,它有3个参数(idnameclass),我希望将每个学生存储在名为{{1}的数组中(只能有7名学生)。

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

我尝试使用固定数组,但我很难让它运行起来。有没有更好的方法来实现这个?

我不能使用Roster或任何STL容器。

student.h

vector

student.cpp

#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

的main.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;
}

4 个答案:

答案 0 :(得分: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];

首先,箭头' - &gt;'与指针一起使用。点'。'与对象一起使用。在这两种情况下,它都可以访问学生的公共成员。

自从你通过

void enroll(Student newStudent)

您应该使用''代替。

newStudent.SomeOfYourMembers;

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

void enroll(Student *newStudent)

然后,你必须使用箭头' - &gt;'像你一样。

回到原始陈述:

newStudent->roster[i];

这意味着,您想要访问Student对象(newStudent)中位置“i”的'roster'数组。正如您在代码中看到的那样,名单未在学生内部声明(并且不应该是因为您需要一系列学生),因此无法使用。

准则

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

然后,如果你需要一个学生阵列,基本上,'名册[i]'会让你访问学生'我'。因此,如果您想要打印学生,您可以这样做:

roster[i].print();

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

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

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

但不要忘记,每次使用new时,都必须通过删除来平衡它。如果你在循环中创建这样的学生,你将必须以同样的方式清理它们:

for(int i = 0; i < SIZE; ++i)
{
    delete roster[i];
}
祝你好运!

如果有任何我可以澄清的内容,请不要犹豫。我希望这有帮助!

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

关于名册数组

不,创建一个可以在main.cpp中声明名单的类名单并不是强制性的。

关键概念是通过定义

Student roster[SIZE]; 

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

什么名单[i] .print()意味着你正在打印该阵列的学生之一,实际上是位于'i'的学生。

关于print()函数

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

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

这样做的好处是,如果您需要在某些方面更改阵列,则print()函数将始终有效。

关于删除

当你在包含对象的数组上做这样的事情时:

delete roster[i];

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

进一步的通知

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

关于容器,固定阵列可能不是最好的完成这项工作。您可能需要查看LinkedList concept

答案 1 :(得分: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;
}

答案 2 :(得分:0)

这个怎么样?

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

Ps:

注册和尺寸不应该是学生班的成员。 理想情况下,打印应该外部化,而应添加ToString函数。

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

Student(int a,string b,string c):id(a),name(b),class(c){}

答案 3 :(得分:0)

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

enroll应该有两个参数:void enroll( Student enrollee, Student Roster[])。您可能应该将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。它存储了学生所在的课程吗?这是他们像大一新生那样在学校的一年吗?

如果您想使用动态分配名单,这是一个不同的故事,但您说它只会有七个学生。