@ixabellol (ず す)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

値が上書きされてしまう

Q&A

Closed

解決したいこと

3人分のデータを読み込んで出力したいのですが、出力時に最後に入力したデータのみが表示されます。自明なコピーコンストラクタで値の上書きをしてしまっていることが原因だと思うのですが、自分では直せませんでした。
わかる方がいましたらば、回答よろしくお願いします。

条件

コンストラクタ関数で変数の入力を行う
データはStudentというテンプレートクラスのメンバとしてまとめる

発生している問題・エラー

ID>>i1
英語の点数>>10
数学の点数>>20
国語の点数>>30
ID>>i2
英語の点数>>40
数学の点数>>50
国語の点数>>60
ID>>i3
英語の点数>>70
数学の点数>>80
国語の点数>>90
i3 70 80 90 240
i3 70 80 90 240
i3 70 80 90 240

該当するソースコード

1 #include<iostream>
2 #include<string>
3 #include<cstring>
4 #include<iomanip>
5 using namespace std; //名前空間
6
7 template<typename T, int N>
8 class Student{ //テンプレートクラス"Student"の宣言
9 public:
10 T data[N];
11 int eng,math,jan,sum;
12 string ID;
13 public:
14 Student(){ //コンストラクタ
15 //cout << "学生ID:" << ID << "のデータを入力" <<endl;
16 for(int i=0; i<N; i++){
17 cout <<"ID>>";
18 cin >> ID;
19 cout << "英語の点数>>";
20 cin >> eng;
21 cout << "数学の点数>>";
22 cin >> math;
23 cout << "国語の点数>>";
24 cin >> jan;
25 sum = eng+math+jan;
26
27 }
28 }
29
30 Student& operator[](int i){
31 return data[i];
32 }
33
34 void show(){
35 for(int i=0; i<N; i++){
36 cout <<ID<<setw(5)<<eng<<setw(5)<<math<<setw(5)<<jan<<setw(5)<<sum<<endl;
37 }
38 }
39
40 };
41
42
43
44 int main(){
45 int eng,math,jan,sum,age,
46 i;
47 string stID, tcID;
48 double eng_avg=0,
49 math_avg=0,
50 jan_avg=0,
51 sum_avg=0;
52
53 Student<int,3> stu;
54
55 stu.show();
56
57 return 0;
58 }

0 likes

3Answer

単純に各IDや点数を上書きしているからでは?
配列なりstd::arrayなりで学生ごとのデータを保持できるようにするべきかと

あと配列dataがどこにも使われてないのですがこれはどういう意図で定義したものですか?

0Like

Comments

  1. @ixabellol

    Questioner

    いろいろ試行錯誤しているうちに混乱してました、すみません…

問題点としては、当該コードですと、eng/math/jan/sumは1人分しか用意されておりません。毎回、同じ領域へ上書きしているので、最後の人のデータしか取り扱えないです。

解決策としては、data同様に、他のメンバ変数(ID/...)もN人分の配列へ拡大することです。

データはStudentというテンプレートクラスのメンバとしてまとめる

おそらくこれは「データ(data)」というメンバ変数があるのではなく、「eng/math/jan」のことを言っていると思われます。テンプレートクラスの課題と考えると、恐らくこの点数を管理する変数型をテンプレートで取り扱いたいのではないか?と類推します。

以上を踏まえるとこんな感じでしょうか?想像が間違っている場合などは適宜修正いただければ幸いに存じます。

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

template < typename T, int N >
class Student { //テンプレートクラス"Student"の宣言
  public:
    string ID[N];
    /* テンプレートで指定された変数型で宣言 */
    T eng[N], math[N], jan[N], sum[N];
  public:
     Student() {
        //cout << "学生ID:" << ID << "のデータを入力" <<endl;
        for (int i = 0; i < N; i++) {
            cout << "ID>>";
            cin >> ID[i];
            cout << "英語の点数>>";
            cin >> eng[i];
            cout << "数学の点数>>";
            cin >> math[i];
            cout << "国語の点数>>";
            cin >> jan[i];
            sum[i] = eng[i] + math[i] + jan[i];
        }
    }

    void show() {
        for (int i = 0; i < N; i++) {
            cout << ID[i] << setw(5)
                 << eng[i] << setw(5) << math[i] << setw(5)
                 << jan[i] << setw(5) << sum[i] << endl;
        }
    }
};

int main()
{
    Student < int, 3 > stu;
//  Student < double, 3 > stu; // 点数が少数込みでもOK
    stu.show();

    return 0;
}

完全な余談

心情的には、Student だったら個人1人分の情報だけを管理したい、かなあ…… 

0Like

Comments

  1. @ixabellol

    Questioner

    返信遅れて申し訳ありません。自分も一人分の情報のみの管理をしたいと思いましたが、学生の課題なのでひとまずはこれでよいかなと。

書き直しましたので、Wandboxのリンクで実行結果を参照してください。一応コードも下にのせておきます。

main.cpp
main.cpp
#include <iostream>
#include <string>
#include <array>
#include <fstream>
#include <cstdlib>

struct Score {
  int english;
  int math;
  int japanese;

  int total() const noexcept {
    return english + math + japanese;
  }
};

std::ostream& operator<<(std::ostream& os, const Score& s) {
  return os << s.english << ' ' << s.math << ' ' << s.japanese
         << ' ' << s.total();
}

std::istream& operator>>(std::istream& is, Score& s) {
  return is >> s.english >> s.math >> s.japanese;
}

struct Student {
  std::string id;
  Score score;
};

std::ostream& operator<<(std::ostream& os, const Student& s) {
  return os << s.id << ' ' << s.score;
}

std::istream& operator>>(std::istream& is, Student& s) {
  return is >> s.id >> s.score;
}

int main() {
  std::array<Student, 3> students;
  
  std::ifstream f("students.txt");
  if (!f.is_open()) {
    return EXIT_FAILURE;
  }

  for (auto&& s : students) {
    f >> s;
  }

  for (auto&& s : students) {
    std::cout << s << std::endl;
  }
}
students.txt
students.txt
i1 10 20 30
i2 40 50 60
i3 70 80 90
0Like

Comments

  1. @ixabellol

    Questioner

    コードまでありがとうございます!参考にさせていただきます。

Your answer might help someone💌