0

宿題用ならこれ。

Student3 つのパラメーター ( idname、 ) を受け取るというクラスがあり、class各生徒をという配列に格納したいと考えてRosterいます (7 人の生徒しか持てません)。

ユーザーは、学生を追加または削除するための入力を提供します。したがって、生徒を作成または削除して配列を管理する必要があります。そのため、ユーザーが学生 ID を指定した場合、配列から彼を削除する必要があります。

固定配列を使用しようとしましたが、機能させるのに苦労しています。これを実装するより良い方法はありますか?

vectorSTL コンテナーを使用してはなりません。

生徒.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;
}

main.cpp

#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;

パラメータが Student へのポインタであった場合

void enroll(Student *newStudent)

次に、矢印「->」を使用する必要があります。

元のステートメントに戻ります。

newStudent->roster[i];

これは、Student オブジェクト (newStudent) 内の位置 'i' にある 'roster' 配列にアクセスする必要があることを意味します。コードでわかるように、名簿は Student 内で宣言されていません (また、Student の配列が必要なため、そうすべきではありません)。これは機能しません。

ガイドライン

前述したように、配列は関数の外にある必要があるため、より高いスコープで使用してください。

次に、生徒の配列が必要な場合は、基本的に「roster[i]」で生徒の「i」にアクセスできます。したがって、学生を印刷したい場合は、次のようにします。

roster[i].print();

「print()」が public として定義されているため、これは有効です。

学生を配列内に保存するには、次のようにします。

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() が意味するのは、その配列の Student の 1 つ、実際には位置 'i' にあるものを印刷していることです。

print()関数について

オブジェクト指向言語の強力な点は、各オブジェクトが同じ print() 関数を持つことです。したがって、配列を文字列に変換する必要はありません。

ただし、文字列を出力 (または返す) したい場合は、このジョブを実行する print() 関数内にコードを記述できます。

これの利点は、さらに何らかの方法で配列を変更する必要がある場合、print() 関数が常に機能することです。

削除について

オブジェクトを含む配列で次のようなことをしている場合:

delete roster[i];

位置「i」のオブジェクトを削除します。したがって、その Student '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 は、学生クラスのメンバーであってはなりません。Print は理想的には外部化する必要があり、代わりに ToString 関数を追加する必要があります。

代わりにインライン コンストラクターの初期化を使用する必要があります。

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

キーワードclassを文字列型の変数名として使用しました。あなたはそれをすべきではありません。そのようにコンパイルしますか?

enroll2 つの引数が必要です: void enroll( Student enrollee, Student Roster[]). これはクラスではなく、通常、クラス名は大文字で始まるため、おそらくRostertoの名前を変更する必要があります。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は何のためにあるのかわかりませんが。生徒が所属しているクラスを保存しますか? 一年生、二年生のような彼らの学年ですか?

ただし、名簿の動的割り当てを使用する場合、それは別の話ですが、学生は7人しかいないとおっしゃいました。

于 2012-06-23T02:33:53.707 に答える