-2

이 이기종 목록을 채우는 데 문제가 있습니다. 텍스트 파일을 전달한 다음이를 사용하여 개체의 멤버 데이터를 채운 다음 목록에 추가합니다. 이것은 이것을 처음 사용하는 것이고 왜 제대로 작동하지 않는지 이해할 수 없습니다. 각 채워진 객체 주소를 포인터 배열의 포인터에 저장해야합니다. 맞습니까? 그러나 테스트 할 때 (* list) [0]의 단일 위치에만 저장된다는 것을 알 수 있습니다. 가장 관련성이 높은 부분은 main.cpp에서 올 것입니다. 고맙습니다!이기종 목록 및 동적 배열 할당

MAIN.CPP

#include <iostream> 
#include <fstream> 
#include <string> 
#include <iomanip> 
#include "student.h" 

using namespace std; 

int main() 
{ 
    string inputFileName; 
    string outputFileName; 

    cout << "Please enter the input file name: "; 
    getline(cin, inputFileName); 

    ifstream inputFile; 
    int NUMBEROFENTRIES; 
    inputFile.open(inputFileName.c_str()); //CLOSE 
    if(inputFile){ 
     NUMBEROFENTRIES = int(inputFile.get())-int('0'); 

    }else{ 
     cout << "Failed to open file." << endl; 
    } 

    Student ** list; //create a pointer to Student pointer 
    list = new Student*[NUMBEROFENTRIES]; //dynamically allocated list of Student pointers 

    for(int i = 0; i < NUMBEROFENTRIES; i++) 
    { 
     string uselessNewLine; 
     getline(inputFile, uselessNewLine); 

     string tempfirstname; 
     string templastname; 
     getline(inputFile, templastname, ','); 
     inputFile.get(); 
     getline(inputFile, tempfirstname); 

     char tempcourse = inputFile.get(); 
     if(tempcourse == 'b'||tempcourse == 'B') 
     { 
      BioStudent bobj; 

      bobj.setNameAndCourse(tempfirstname, templastname, tempcourse); 

      string garbage; 
      getline(inputFile, garbage, ' '); 

      bobj.SetGrades(inputFile); 

      list[i] = &bobj; //I assume this is where the error is but i should be incrementing? 

     } 

     else if(tempcourse == 't' || tempcourse == 'T') 
     { 
      TheaterStudent tobj; 

      tobj.setNameAndCourse(tempfirstname, templastname, tempcourse); 

      string garbage; 
      getline(inputFile, garbage, ' '); 

      tobj.SetGrades(inputFile); 

      list[i] = &tobj; //I assume this is where the error is but i should be incrementing? 


     } 

     else if(tempcourse == 'c' || tempcourse == 'C') 
     { 
      CompsciStudent cobj; 

      cobj.setNameAndCourse(tempfirstname, templastname, tempcourse); 

      string garbage; 
      getline(inputFile, garbage, ' '); 
      getline(inputFile, garbage, ' '); 

      cobj.SetGrades(inputFile); 

      list[i] = &cobj; //I assume this is where the error is but i should be incrementing? 



     }else{ 
      cout << "ERROR" << endl; 
     } 

     cout << (*list[0]).course << endl; 

    } 



    delete [] list; 
    return 0; 
} 

student.h

#include <string> 
#include <iostream> 
using namespace std; 


class Student 
{ 
public: 
    virtual double GetAverage()=0; //Another pure virtual function 
    void setNameAndCourse(string fn, string ln, char tc); 
    Student(); 
    char course; 
    char GetCourse(); 
protected: 

    string firstName; 
    string lastName; 


private: 

}; 


class BioStudent: public Student 
{ 
public: 
    BioStudent(); 
    void SetGrades(ifstream &input); 
    double GetAverage(); 

private: 
    int labGrade; 
    int test1; 
    int test2; 
    int test3; 
    int finalExam; 

}; 


class TheaterStudent: public Student 
{ 
public: 
    TheaterStudent(); 
    void SetGrades(ifstream &input); 
    double GetAverage(); 

private: 
    int participation; 
    int midterm; 
    int finalExam; 

}; 


class CompsciStudent: public Student 
{ 
public: 
    CompsciStudent(); 
    void SetGrades(ifstream &input); 
    double GetAverage(); 

private: 
    int assign1; 
    int assign2; 
    int assign3; 
    int assign4; 
    int assign5; 
    int assign6; 
    double assignAverage; 
    int test1; 
    int test2; 
    int finalExam; 
}; 

student.cpp

#include "student.h" 
#include <iostream> 
#include <iomanip> 
#include <string> 
#include <fstream> 

using namespace std; 

Student::Student() 
{ 
    firstName = ""; 
    lastName = ""; 
    course = ' '; 
} 

void Student::setNameAndCourse(string fn, string ln, char tc) 
{ 
    firstName = fn; 
    lastName = ln; 
    course = tc; 

} 

char Student::GetCourse() 
{ 
    return course; 
} 

BioStudent::BioStudent() 
{ 
    labGrade = 0; 
    test1 = 0; 
    test2 = 0; 
    test3 = 0; 
    finalExam = 0; 
} 

void BioStudent::SetGrades(ifstream& input) 
{ 
    input >> labGrade; 
    input >> test1; 
    input >> test2; 
    input >> test3; 
    input >> finalExam; 

} 

double BioStudent::GetAverage() 
{ 
    double toReturn = 0.0; 
    toReturn = ((labGrade*.3) + (test1*.15) + (test2*.15) + (test3*.15) + (finalExam*.25)); 
    return toReturn; 
} 

TheaterStudent::TheaterStudent() 
{ 
    participation = 0; 
    midterm = 0; 
    finalExam = 0; 
} 

void TheaterStudent::SetGrades(ifstream &input) 
{ 
    input >> participation; 
    input >> midterm; 
    input >> finalExam; 

} 

double TheaterStudent::GetAverage() 
{ 
    double toReturn = 0.0; 
    toReturn = ((participation*.4)+(midterm*.25)+(finalExam*.35)); 
    return toReturn; 
} 

CompsciStudent::CompsciStudent() 
{ 
    assign1 = 0; 
    assign2 = 0; 
    assign3 = 0; 
    assign4 = 0; 
    assign5 = 0; 
    assign6 = 0; 
    assignAverage = 0.0; 
    test1 = 0; 
    test2 = 0; 
    finalExam = 0; 
} 

void CompsciStudent::SetGrades(ifstream &input) 
{ 
    input >> assign1; 
    input >> assign2; 
    input >> assign3; 
    input >> assign4; 
    input >> assign5; 
    input >> assign6; 
    input >> test1; 
    input >> test2; 
    input >> finalExam; 

} 

double CompsciStudent::GetAverage() 
{ 
    double toReturn = 0.0; 
    assignAverage = ((assign1+assign2+assign3+assign4+assign5+assign6)/6); 
    toReturn = ((assignAverage*.3)+(test1*.2)+(test2*.2)+(finalExam*.3)); 
    return toReturn; 
} 
+2

'list [i] = & bobj' - 만료 예정인 자동 변수의 주소를 저장하여 그 주소를 쓸모 없게 만들었습니다. 마찬가지로이 코드에서 다른 모든 유사한 저장합니다. 'std :: vector >'또는 이와 유사한 관리 형 포인터 솔루션을 사용하는 것이 좋습니다. – WhozCraig

+1

동적 메모리 할당을 배우는 것이 아니라면하지 마십시오. 대신 [표준 컨테이너] (http://en.cppreference.com/w/cpp/container)를 사용하십시오 (나는''std :: vector' ''를 권장합니다 (http://en.cppreference.com/w/cpp/)). 컨테이너/벡터)를 시작합니다. 또한 컨테이너에있는 객체에 대한 포인터를 저장하지 말고 실제 객체 인스턴스를 저장하십시오. 마지막으로, 당신이 만드는 것은 단어의 컴퓨터 과학 의미에서 "목록"이 아니라 오히려 객체에 대한 동적 인 크기의 배열 (포인터)입니다. –

+1

"컨테이너의 오브젝트 인스턴스"는 다형성 인 경우 오브젝트 분할로 연결됩니다. 여기서는 그렇지 않지만주의해야 할 점은 std :: vector는 내부 버퍼를 재 할당 할 수 있으므로 객체가 이동할 수 있습니다. 이들에 대한 포인터 또는 참조가 필요하면 유효하지 않게됩니다. 따라서 우리는 재 할당되지 않은 컨테이너 (예 : std :: list) 또는 포인터 (-> WhozCraig의 주석)로 되돌아 가야합니다. – Aconcagua

답변

0

당신은 맞이다

list[i] = &bobj; //I assume this is where the error is but i should be incrementing? 

다음과 같이 bobj 스택에 정의되어 있기 때문에 그 이유는 다음과 같습니다 : t는, 문제는 여기에있다

BioStudent bobj; 
그래서

포위 범위가 끝나면이 파괴되고, 다음 목록은 것이다 매달려있는 포인터를 잡아라.

당신이 원하는 것은 동적으로 할당되는 개체 : 다음

BioStudent* bobj = new BioStudent; 

과 :

list[i] = bobj; 

은 또한 당신의 객체의 할당을 해제하는 것을 잊지 말아, 또는보다 효율적으로 사용하는 스마트 포인터.

+0

아, 굉장 해요! 동적 할당에 대해 혼란 스러울뿐입니다. 오늘 밤 나중에 비디오를 볼 것입니다. 언제 할당을 해제 할 최적의 시간이 될까요? 그건 '보비 삭제'부분에요? – SWilt

+0

@SWilt는 delete [] list 바로 전에 할당을 해제합니다. 또 다른 것은 Student 클래스에 가상 소멸자가 필요하다는 것입니다. 그렇지 않으면 정의되지 않은 동작이 생깁니다. 자세한 내용은 http://stackoverflow.com/questions/8599225/virtual-destructor-and-undefined-behavior를 참조하십시오. – marcinj