查看完整版本: [已解決]若類別中有一結構成員的成員是string,如何cout該字串
頁: [1]

opchta 發表於 2017-2-5 03:15 PM

[已解決]若類別中有一結構成員的成員是string,如何cout該字串

本帖最後由 opchta 於 2017-2-5 09:24 PM 編輯

●【所遇問題描述】:
各位大大好,
小弟最近在練習C++的物件導向遇到了一些問題。
小弟想將練習用類別寫一個讀取、計算學生成績的程式,所以宣告了類別去儲存學生的基本資訊,像是名字、姓別還有成績等等,在類別中也宣告了兩個方法:平均GradeMean、加權平均WeightGrade,其他的私有成員則都是加權平均的權重。
首先小弟new一個類別的陣列,並使用函數ReadGrade 將txt檔中的成績讀入,讀入後使用GradeMean 及WeightGrade 兩個方法計算每位學生的成績平均以及加權平均。最後嘗試將計算的結果寫入另一個txt檔,同時將一、二個結果輸出在command widows上。小弟的程式碼只要求輸出其中一個成員name,但程式卻將我所有的成員都輸出了。
我有上網查過許多資料,也問了一、二個寫程式比我厲害的朋友,但都查不出原因出在哪,請問各位大大,我這個寫法是哪裡出錯了?我想輸出的結構成員是string,我在想是不是因為類別包類別才會出錯?

●【編譯環境】:
Dev C++ 5.7.1的專案

●【目前程式碼】:
我在標頭檔StudentData.h 中宣告的類別:

#ifndef DEF_CLASS
        #define DEF_CLASS
        #include <string>
        
        using namespace std;
        
        typedef struct
        {
                string name;
                string Gender;
                string StudentID;
        
        }Student;
        
        typedef struct
        {
                double Chinese;
                double Math;
                double English;
                double Physic;
                double Chemical;
        }Grade;
        
        class StudentData
        {
                public:
                        Student student_infom;
                        Grade AllGrade;
                        
                        StudentData();
                        ~StudentData();
                        
                        void InitialStruct();
                        double GradeMean(Grade AllGrade);
                        double WeightGrade(Grade AllGrade);
                                
                private:
                        double WeightOfChins;
                        double WeightOfMath;
                        double WeigetOfEng;
                        double WeightOfPhy;
                        double WeightOfChem;
        };
#endif


下面這是我在程式StudentData.cpp 中建講類別的方法的程式碼

#include "StudentData.h"

using namespace std;

StudentData::StudentData()
{
        
}

StudentData::~StudentData()
{
        
}

double StudentData::GradeMean(Grade AllGrade)
{
        double sum, Mean;
        
        sum = AllGrade.Chinese + AllGrade.Math + AllGrade.English + AllGrade.Physic + AllGrade.Chemical;
        
        return Mean = sum / 5;
}

double StudentData::WeightGrade(Grade AllGrade)
{
        WeightOfChins = 0.3;
        WeightOfMath = 0.2;
        WeigetOfEng = 0.3;
        WeightOfPhy = 0.1;
        WeightOfChem = 0.1;
        
        return AllGrade.Chinese * WeightOfChins + AllGrade.Math * WeightOfMath + AllGrade.English * WeigetOfEng + AllGrade.Physic * WeightOfPhy + AllGrade.Chemical * WeightOfChem;
}

void StudentData::InitialStruct()
{
        student_infom.name = "name";
        student_infom.Gender = "gender";
        student_infom.StudentID = "000000000";

        AllGrade.Chinese = 0.0;
        AllGrade.Math = 0.0;
        AllGrade.English = 0.0;
        AllGrade.Physic = 0.0;
        AllGrade.Chemical = 0.0;
}


這是我的主程式:  
#include <string>
#include <string.h>
#include <cstdlib>
#include "StudentData.h"

using namespace std;

double String2Num(string InputStr)
{
        int NumberLen = InputStr.size();
        int i;
        double ReturnNum;
        char *NumberChar = new char;
        for(i = 0; i < NumberLen; i++)
                *(NumberChar + i) = InputStr;
        
        ReturnNum = atof(NumberChar);
        delete [] NumberChar;
        return ReturnNum;
}

void WriteGrade(char* filename, int StudentsNum, StudentData* A_Class)
{
        fstream file;
        int i, j;
        char Name;
        string Title;
        
        file.open(filename, ios::out);
        if(file.fail())
        {
                cout << "File I/O is failed ! "<< endl;
        }
        else
        {
                file << "─ Class Grade ─" << endl;
                for(i = 0; i < StudentsNum; i++)
                {
                        file << A_Class.student_infom.name << "\'s Grade Mean: " << A_Class.GradeMean(A_Class.AllGrade) << endl;
                }
                        
               
                file << "\n" << "─ Class Weight Mean ─" << endl;
                for(i = 0; i < StudentsNum; i++)
                        file << A_Class.student_infom.name << "\'s Grade Mean: " << A_Class.WeightGrade(A_Class.AllGrade) << endl;
               
                file << "\n" << "**************************************************大家好,我是分隔線XD********************************************************" << endl;
        }
        file.close();
}

void ReadGrade(char* filename, int RowNum, StudentData* A_Class)
{
        fstream file;
        string LineTemp, BeTransTemp;
        int flag = 0, i = 0, index;
        int beganPoint = 0, endPoint = 0;
        string tempString;
        
        file.open(filename);
        if (!file)
        {
                cout << "File I/O is failed ! "<< endl;
        }
        else
        {
                while(i < RowNum)
                {
                        getline(file, LineTemp);
                        index = 0;
                        while(flag < 7)
                        {
                                if(LineTemp == ' ')
                                {
                                        switch(flag)
                                        {        
                                                case 0:
                                                        endPoint = index;
                                                        A_Class.student_infom.name.assign(LineTemp, 0, endPoint - beganPoint);
                                                        break;
                                                case 1:
                                                        beganPoint = endPoint + 1;
                                                        endPoint = index;
                                                        A_Class.student_infom.Gender.assign(LineTemp, beganPoint, endPoint - beganPoint);
                                                        break;
                                                case 2:
                                                        beganPoint = endPoint + 1;
                                                        endPoint = index;
                                                        A_Class.student_infom.StudentID.assign(LineTemp, beganPoint, endPoint - beganPoint);
                                                        break;
                                                case 3:
                                                        beganPoint = endPoint + 1;
                                                        endPoint = index;
                                                        BeTransTemp.assign(LineTemp, beganPoint, endPoint - beganPoint);
                                                        A_Class.AllGrade.Chinese = String2Num(BeTransTemp);
                                                        break;
                                                case 4:
                                                        beganPoint = endPoint + 1;
                                                        endPoint = index;
                                                        BeTransTemp.assign(LineTemp, beganPoint, endPoint - beganPoint);
                                                        A_Class.AllGrade.Math = String2Num(BeTransTemp);
                                                        break;
                                                case 5:
                                                        beganPoint = endPoint + 1;
                                                        endPoint = index;
                                                        BeTransTemp.assign(LineTemp, beganPoint, endPoint - beganPoint);
                                                        A_Class.AllGrade.English = String2Num(BeTransTemp);
                                                        break;
                                                case 6:
                                                        beganPoint = endPoint + 1;
                                                        endPoint = index;
                                                        BeTransTemp.assign(LineTemp, beganPoint, endPoint - beganPoint);
                                                        A_Class.AllGrade.Physic = String2Num(BeTransTemp);
                                                        
                                                        beganPoint = endPoint + 1;
                                                        endPoint = LineTemp.size();
                                                        BeTransTemp.assign(LineTemp, beganPoint, endPoint - beganPoint);
                                                        A_Class.AllGrade.Chemical = String2Num(BeTransTemp);
                                                        break;
                                                default:
                                                        break;
                                        }
                                       
                                        flag++;
                                }
                                
                                index++;
                        }
                        flag = 0;
                        i++;
                }
        }
        
        file.close();
}

int main(int argc, char** argv) {
        int n = 5;
        StudentData *A_Class = new StudentData;
        
        //string path = "D:\\Document\\program\\自己額外的練習\\用類別及方法儲存、計算班級成績\\";
        char path[] = "D:\\hacker station of SC\\practice of program\\用類別及方法儲存、計算班級成績\\";
        char file[] = "test_EN.txt";
        char filename;
        strcpy(filename, path);
        strcat(filename, file);
        
        char SaveFile[] = "ClassGrade.txt";
        char SaveFilename;
        strcpy(SaveFilename, path);
        strcat(SaveFilename, SaveFile);
        
        ReadGrade(filename, 5, A_Class);
        
        cout << A_Class.student_infom.name << "\'s mean:" << A_Class.GradeMean(A_Class.AllGrade) << endl;
        cout << (A_Class + 4)->student_infom.name << "\'s mean:" << A_Class.WeightGrade(A_Class.AllGrade) << endl;
        
        WriteGrade(SaveFilename, 5, A_Class);
        
        delete [] A_Class;
        
        system("pause");
        return 0;
}


我txt檔中的內容是這樣:
Bill male 499210457 95 96 92 99 95
Milala female 604689666 90 95 98 76 80
Jeffery male 499568975 90 90 89 90 82
Cindy female 499635895 92 80 96 76 79
Simon male 699689859 95 99 92 96 95


●【目前執行結果】:
在cmd中顯示的結果是這樣:
Simon male 699689859 95 99 92 96 95's mean:95.4
Simon male 699689859 95 99 92 96 95's mean:95

在新的txt檔中顯示的內容是這樣:
─ Class Grade ─
Bill's Grade Mean: 95.4
Milala female 604689666 90 95 98 76 80's Grade Mean: 87.8
Jeffery male 499568975 90 90 89 90 82's Grade Mean: 88.2
Cindy female 499635895 92 80 96 76 79's Grade Mean: 84.6
Simon male 699689859 95 99 92 96 95's Grade Mean: 95.4

─ Class Weight Mean ─
Bill's Grade Mean: 94.7
Milala female 604689666 90 95 98 76 80's Grade Mean: 91
Jeffery male 499568975 90 90 89 90 82's Grade Mean: 88.9
Cindy female 499635895 92 80 96 76 79's Grade Mean: 87.9
Simon male 699689859 95 99 92 96 95's Grade Mean: 95

**************************************************大家好,我是分隔線XD********************************************************


●【期望執行結果】:
希望在cmd中顯示的結果是這樣:
Simon's mean:95.4
Simon's mean:95

希望在新的txt檔中顯示的內容是這樣:
─ Class Grade ─
Bill's Grade Mean: 95.4
Milala's Grade Mean: 87.8
Jeffery's Grade Mean: 88.2
Cindy's Grade Mean: 84.6
Simon's Grade Mean: 95.4

─ Class Weight Mean ─
Bill's Grade Mean: 94.7
Milala's Grade Mean: 91
Jeffery's Grade Mean: 88.9
Cindy's Grade Mean: 87.9
Simon's Grade Mean: 95

**************************************************大家好,我是分隔線XD********************************************************




...<div class='locked'><em>瀏覽完整內容,請先 <a href='member.php?mod=register'>註冊</a> 或 <a href='javascript:;' onclick="lsSubmit()">登入會員</a></em></div><div></div>

snowflying 發表於 2017-2-5 06:58 PM

你的程式碼在名字處理上有問題,所以後面的那些都一起被放入名字裡了

ReadGrade 的 else
裡面改成

while(i < RowNum)
{
    file >> A_Class.student_infom.name
         >> A_Class.student_infom.Gender
         >> A_Class.student_infom.StudentID
         >> A_Class.AllGrade.Chinese >> A_Class.AllGrade.Math >> A_Class.AllGrade.English
         >> A_Class.AllGrade.Physic >> A_Class.AllGrade.Chemical;
               
    i++;        
}


WeightGrade(Grade AllGrade)
GradeMean(Grade AllGrade)

不需要傳參數,直接用同 class 裡面的成員
改成

WeightGrade()
GradeMean()

還有 String2Num,不用寫得那麼複雜


double String2Num(string InputStr)
{
    return atof(InputStr.c_str());
}



...<div class='locked'><em>瀏覽完整內容,請先 <a href='member.php?mod=register'>註冊</a> 或 <a href='javascript:;' onclick="lsSubmit()">登入會員</a></em></div>

opchta 發表於 2017-2-5 08:22 PM

本帖最後由 opchta 於 2017-2-5 08:40 PM 編輯

非常感恩大大~~~~~!
照大大的方法,果然可以吔,不過我還是很好奇,為什麼我的方法不行。
我的方法是:找到空格後,用flag做為標記,並將前一次的最終點設為起始點beginPoint;該次找到的空格做為終點endPoint,並將這之間的字串存進成員中。這樣的做法為什麼會出錯呢?會這樣寫是因為我找到的資料都是類似的做法,或是大大給我一個方向,讓我了解相關的知識。
還有,請問使用
file >...<div class='locked'><em>瀏覽完整內容,請先 <a href='member.php?mod=register'>註冊</a> 或 <a href='javascript:;' onclick="lsSubmit()">登入會員</a></em></div>

snowflying 發表於 2017-2-5 09:10 PM

opchta 發表於 2017-2-5 08:22 PM static/image/common/back.gif
非常感恩大大~~~~~!
照大大的方法,果然可以吔,不過我還是很好奇,為什麼我的方法不行。
我的方法是:找 ...

每一次進入 while(flag < 7) 之前
都應該執行 beganPoint = 0, endPoint = 0;
但你只有執行一次,所以會錯

fstream 繼承了 iostream
file >> 就跟 cin >> 一樣,以空白字元 ('\n'、'\t'、' '、...) 分隔
應該比起那個寫法還要好,能處理其他空白字元,寫法也比較簡潔,比較少 bug

理論上給定初始值應該在 constructor 才對
寫在 WeightGrade() 裡面,每次執行都給值,不太好
...<div class='locked'><em>瀏覽完整內容,請先 <a href='member.php?mod=register'>註冊</a> 或 <a href='javascript:;' onclick="lsSubmit()">登入會員</a></em></div>
頁: [1]