Εργαστήριο Τεχνολογίας Λογισμικού
+2 votes
481 views

Καλησπέρα. Με τη φόρα που πήρα στις ασκήσεις έρχονται και οι απορίες. Άλλος ένας προβληματισμός. Λύνω την άσκηση 11.21 του βιβλίου όπου ζητάει να φτιαχτεί ένα πρόγραμμα που θα διαβάζει βαθμολογίες 3 μαθημάτων σε 10 μαθητές, θα τις καταχωρίζει σε πίνακα, θα υπολογίζει το μέσο όρο κάθε μαθητή και θα εμφανίζει το πλήθος που πέτυχε και απέτυχε. Τώρα, προσπαθώντας να γράψω τον κώδικα όρισα private και public μέλη μιας κλάσης αλλά όταν φτάνω στο δια ταύτα, δηλαδή πχ. στην εισαγωγή πρώτου μαθήματος ("Εισαγωγή πρώτου μαθήματος για φοιτητές"), το μέλος ma8ima_1 στο cin >> stnts[i].ma8ima_1; , το θεωρεί "inaccessible"! Τι πάει στραβά; Ευχαριστώ

// χώρος ονομάτων
using namespace std;

const size_t NO_STUDENT{ 10 };

// Κλάση student
class student {
private:
	int ma8ima_1{};
	int ma8ima_2{};
	int ma8ima_3{};
public:
	student() {};
	student(float a, float b, float c) : ma8ima_1(a), ma8ima_2(b), ma8ima_3(c) {}
	float getaverage() { return (ma8ima_1 + ma8ima_2 + ma8ima_3) / 3.0; }
} stnts[NO_STUDENT];

int main()
{
	//Εισαγωγή πρώτου μαθήματος για φοιτητές
	cout << "dwse ba8mous sto prwto ma8ima" << endl;
	for (int i = 0; i < NO_STUDENT; ++i)
		cin >> stnts[i].ma8ima_1;

	//Εισαγωγή δεύτερου μαθήματος για φοιτητές
	cout << "dwse ba8mous sto deutero ma8ima" << endl;
	for (int i = 0; i < NO_STUDENT; ++i)
		cin >> stnts[i].ma8ima_2;

	//Εισαγωγή τρίτου μαθήματος για φοιτητές
	cout << "dwse ba8mous sto trito ma8ima" << endl;
	for (int i = 0; i < NO_STUDENT; ++i)
		cin >> stnts[i].ma8ima_3;

	//εκτύπωση του πίνακα των αντικειμένων φοιτητές με τα 3 μαθήματα στον καθένα
	for (int i = 0; i < NO_STUDENT; ++i) {
		cout << stnts[i].ma8ima_1 << '\n';
		cout << stnts[i].ma8ima_2 << '\n';
		cout << stnts[i].ma8ima_3 << '\n';
	}

	int count1{}, count2{};

	//Υπολογισμός μέσου όρου κάθε φοιτητή
	for (int i = 0; i < NO_STUDENT; ++i) {
		const float av{ stnts[i].average() };

		if (av < 9.5) {
			cout << i + 1 << " apetuxe\n";
			++count1;
		}
		else
			if (av > 18.5) {
				cout << i + 1 << " petuxe\n";
				++count2;
			}
	}

	//εκτύπωση ποιοι απέτυχαν και ποιοι πέτυχαν
	cout << "apetuxan: " << count1 << " foitites" << " se pososto  " << count1 / (NO_STUDENT + 0.0) * 100.0 << "%\n";
	cout << "petuxan: " << count2 << " foitites" << " se pososto  " << count2 / (NO_STUDENT + 0.0) * 100.0 << "%\n";
	return 0;
}
in progintro by (820 points) | 481 views

1 Answer

+1 vote

Πρόσεξε λίγο εδώ:

 cout << "dwse ba8mous sto prwto ma8ima" << endl;
    	for (int i = 0; i < NO_STUDENT; ++i)
    		cin >> stnts[i].ma8ima_1;

Στο cin >> stnts[i].ma8ima_1;:
Το νόημα των private members είναι το να μην μπορούν να τα διαχειριστούν άλλοι εκτός της ίδιας της κλάσης (δηλαδή, κώδικας των μεθόδων της).

Για να δουλέψει το παράδειγμά σου μπορείς να δημιουργήσεις συναρτήσεις get/set για τις private τιμές, πχ:

void setMathima1(int a) { mathima1 = a; }
int getMathima1() { return mathima1; }

και κάθε φορά που επιθυμείς να διαβάσεις/γράψεις σε αυτές να καλείς την αντίστοιχη μέθοδο.

Επίσης, ακόμα πιο σωστό θα ήταν να χρησιμοποιήσεις τους constructors που δέχονται τα μαθήματα ως παραμέτρους, και να κατασκευάζεις απευθείας τον μαθητή με όλους τους βαθμούς του.
πχ:

cin >> a >> b >> c;
student mathitis(a, b, c);

Κάτι τελευταίο: ο υπολογισμός του μέσου όρου του κάθε μαθητή εξαρτάται από τους βαθμούς του μαθητή, επομένως θα ταίριαζε πολύ να δημιουργήσεις μια μέθοδο στην κλάση student, όπως float calculateAverageGrade(), που να υπολογίζει και να επιστρέφει τον μέσο όρο.
Οπότε εν τέλει να το χρησιμοποιείς με αυτό τον τρόπο:

cout << student1.calculateAverageGrade() << endl;

το οποίο μου φαίνεται πιο καθαρό, και σου μειώνει πολύ τις γραμμές κώδικα εκτός της κλάσης student :D

by (3.0k points)
edited by
+1

Ευχαριστώ θερμά! Οπότε δηλαδή πρέπει, εφόσον δηλώσω private μεταβλητές, για κάθε μια μεταβλητή να βάλω και την αντίστοιχη void set (η οποία μάλλον επιτρέπει την πρόσβαση απο τη main) και επίσης και την αντίστοιχη get (η οποία μάλλον επιτρέπει να δοθεί η τιμή η οποία δίδεται στη main απο εμας). Άρα θέλω για κάθε μια μεταβλητή μια set και μια get για τους παραπάνω λόγους;

Αυτό με τον constructor το σκέφτηκα αλλά προτίμησα το loop γιατί ήταν 10 μαθητές και ήταν ήδη μειωμένοι. Η άσκηση έλεγε 50. Απο χθες τώρα θα τελείωνα αν ήταν να βάλω τιμές σε 50 ή 100+ αντικείμενα - μαθητές. Ευχαριστώ πάντως !

Σχετικά με τη μέθοδο, έχω δημιουργήσει την

float getaverage() { return (ma8ima_1 + ma8ima_2 + ma8ima_3) / 3.0; }

Απλά δε τη χρησιμοποιώ για κάθε ένα ξεχωριστά αλλά σε loop για όλα μαζί τα αντικείμενα γιατί τα αντικείμενα στον πίνακα ήταν κάπως επαρκή (10), διαχειρίσιμα μεν τα 10, αλλά είναι προπόνηση για στιγμές που θα έχω πολύ περισσότερα (πχ. 100+) οπότε εκεί θα είναι αδύνατο να γράφω ξεχωριστά για 100+ αντικείμενα.

Edit: Πάντως, παρότι τα προσέθεσα, πάλι σφάλματα παίρνω

+1

για να μπορέσω να σε βοηθήσω και εγώ καλύτερα, μπορείς να στείλεις σε text (copy paste) τον κώδικά σου έτσι ώστε να τον τρέξω/αλλάξω για να δώ τι κάνεις ακριβώς

+1

Φυσικά και μπορώ , και ευχαριστώ εκ των προτέρων γι' αυτό. Τον παραθέτω παρακάτω ολόκληρο:

// Βιβλιοθήκες (Headers)
#include <iostream>
#include <string>
#include <cmath>
#include <algorithm>
#include <cstdio>

// Χώρος ονομάτων
using namespace std;

const size_t NO_STUDENT{ 10 };

// Class student
class student {
private:
	int ma8ima_1{};
	int ma8ima_2{};
	int ma8ima_3{};
public:
       void set_Ma8ima_1(int a) { ma8ima_1 = a; }
       int get_Ma8ima_1() { return ma8ima_1; }
      void set_Ma8ima_2(int b) { ma8ima_2 = b; }
      int get_Ma8ima_2() { return ma8ima_2; }
      void set_Ma8ima_3(int c) { ma8ima_3 = c; }
      int get_Mathima_3() { return ma8ima_3; }
	student() {};
	student(float a, float b, float c) : ma8ima_1(a), ma8ima_2(b), ma8ima_3(c) {}

	float average() { return (ma8ima_1 + ma8ima_2 + ma8ima_3) / 3.0; }
} stnts[NO_STUDENT];

int main()
{
	//βαθμοί για πρώτο μάθημα
	cout << "dwse ba8mous sto prwto ma8ima" << endl;
	for (int i = 0; i < NO_STUDENT; ++i)
		cin >> stnts[i].ma8ima_1;

	// βαθμοί για δεύετρο μάθημα
	cout << "dwse ba8mous sto deutero ma8ima" << endl;
	for (int i = 0; i < NO_STUDENT; ++i)
		cin >> stnts[i].ma8ima_2;

	// βαθμοί για τρίτο μάθημα
	cout << "dwse ba8mous sto trito ma8ima" << endl;
	for (int i = 0; i < NO_STUDENT; ++i)
		cin >> stnts[i].ma8ima_3;

	//εκτύπωση πίνακα
	for (int i = 0; i < NO_STUDENT; ++i) {
		cout << stnts[i].ma8ima_1 << '\n';
		cout << stnts[i].ma8ima_2 << '\n';
		cout << stnts[i].ma8ima_3 << '\n';
	}

	int count1{}, count2{};

	//Μέσος όρος
	for (int i = 0; i < NO_STUDENT; ++i) {
		const float av{ stnts[i].average() };

		if (av < 9.5) {
			cout << i + 1 << " apetuxe\n";
			++count1;
		}
		else
			if (av > 18.5) {
				cout << i + 1 << " petuxe\n";
				++count2;
			}
	}

	//εκτύπωση επιτυχιών και αποτυχιών
	cout << "apetuxan: " << count1 << " foitites" << " se pososto  " << count1 / (NO_STUDENT + 0.0) * 100.0 << "%\n";
	cout << "petuxan: " << count2 << " foitites" << " se pososto  " << count2 / (NO_STUDENT + 0.0) * 100.0 << "%\n";
	return 0;
}
0

Το πρώτο που βλέπω εγώ (που να εξηγεί γιατί δεν δουλεύει το πρόγραμμα σου) είναι ότι δεν χρησιμοποιείς τις συναρτήσεις get & set που όρισες για το κάθε μάθημα, αρα ουσιαστικά δεν έχει αλλάξει κάτι από πριν.
Αυτό που θες είναι κάτι της μορφής:

int grade;
cin >> grade;
stnts[i].set_Ma8ima_1(grade);

και αντίστοιχα για τις συναρτήσεις get.

Edit: Και με αρκετό zoom in, βλέπω ότι και αυτό το πρόβλημα σου βγάζει και το visual studio (οτι προσπαθείς να προσπελάσεις private μεταβλητές).

0

Ευχαριστώ για την απάτνηση Lonias. Η απάντησή μου είναι "αμ δε!". Τα έχω δοκιμάσει και έτσι και πάλι δεν τις βλέπει τις μεταβλητές..

0

Θελεις να γίνεις πιο συγκεκριμένος; Το έτρεξα με τις αλλαγές που σου προτείναμε και έτρεχε κανονικά.

0

Οκ, τότε μάλλον κάτι μου διαφεύγει το οποίο δε μπορώ να βρω. Δίνω τον κώδικα απο κάτω ώστε να μου πείτε τι μου διαφεύγει ή δεν έχω κάνει και σε μένα δεν τρέχει. Ευχαριστώ πολύ και πάλι

#include <iostream>
#include <string>
#include <cmath>
#include <algorithm>
#include <cstdio>

// Χώρος ονομάτων
using namespace std;

const size_t NO_STUDENT{ 10 };

// Class student
class student {
private:
	int ma8ima_1{};
	int ma8ima_2{};
	int ma8ima_3{};
public:
       void set_Ma8ima_1(int a) { ma8ima_1 = a; }
int get_Ma8ima_1() { return ma8ima_1; }
void set_Ma8ima_2(int b) { ma8ima_2 = b; }
int get_Ma8ima_2() { return ma8ima_2; }
void set_Ma8ima_3(int c) { ma8ima_3 = c; }
int get_Ma8ima_3() { return ma8ima_3; }
	student() {};
	student(float a, float b, float c) : ma8ima_1(a), ma8ima_2(b), ma8ima_3(c) {}

	float average() { return (ma8ima_1 + ma8ima_2 + ma8ima_3) / 3.0; }
} stnts[NO_STUDENT];

int main()
{
     int a, b, c;
	//βαθμοί για πρώτο μάθημα
	cout << "dwse ba8mous sto prwto ma8ima" << endl;
	for (int i = 0; i < NO_STUDENT; ++i){
		cin >> a;
       cout << stnts[i].set_ma8ima_1(a);
    }
	// βαθμοί για δεύετρο μάθημα
	cout << "dwse ba8mous sto deutero ma8ima" << endl;
	for (int i = 0; i < NO_STUDENT; ++i) {
		cin >> b;
        cout << stnts[i].set_ma8ima_2(b);
    }
	// βαθμοί για τρίτο μάθημα
	cout << "dwse ba8mous sto trito ma8ima" << endl;
	for (int i = 0; i < NO_STUDENT; ++i) {
		cin >> c;
        cout << stnts[i].set_ma8ima_3(c);
    }

	//εκτύπωση πίνακα
	for (int i = 0; i < NO_STUDENT; ++i) {
		cout << stnts[i].ma8ima_1 << '\n';
		cout << stnts[i].ma8ima_2 << '\n';
		cout << stnts[i].ma8ima_3 << '\n';
	}

	int count1{}, count2{};

	//Μέσος όρος
	for (int i = 0; i < NO_STUDENT; ++i) {
		const float av{ stnts[i].average() };

		if (av < 9.5) {
			cout << i + 1 << " apetuxe\n";
			++count1;
		}
		else
			if (av > 18.5) {
				cout << i + 1 << " petuxe\n";
				++count2;
			}
	}

	//εκτύπωση επιτυχιών και αποτυχιών
	cout << "apetuxan: " << count1 << " foitites" << " se pososto  " << count1 / (NO_STUDENT + 0.0) * 100.0 << "%\n";
	cout << "petuxan: " << count2 << " foitites" << " se pososto  " << count2 / (NO_STUDENT + 0.0) * 100.0 << "%\n";
	return 0;
}
0

Δεν εχεις χρησιμοποιήσει τις συναρτήσεις get_Ma8ima_i οταν πας να τυπώσεις τις τιμές.
Θα πρέπει αντίστοιχα να κάνεις:

int c;
c = stnts[i].get_Ma8ima_1();
cout << c << '\n';
0

Καλημέρα και ευχαριστώ για την απάντηση και την ενασχόληση. Λάθος μου! Είχα βάλει κατα λάθος την set σε operator cout (το οποίο προφανώς δε δουλεύει αφού ειναι void) αντι να βάλω get και επίσης δεν είχα βάλει get στην εκτύπωση. Τώρα το τρέχει τον κώδικα κανονικά, ωστόσο, όταν φτάνει στην εκτύπωση, μου βγάζει άλλα αντί άλλων! Εκεί διαπιστώνω ότι μου εμφανίζει όλο μηδενικά και όχι τις τιμές που έχω θέσει εγώ στο cin, άρα κατ' επέκταση βγαίνει και μηδέν ο μέσος όρος κάθε φοιτητή και άρα το αποτέλεσμα είναι 100% αποτυχία ότι βαθμούς και αν βάλω σε όλους τους φοιτητές.

Ο κώδικας είναι:

// Class student
class student {
private:
	int ma8ima_1{};
	int ma8ima_2{};
	int ma8ima_3{};
public:
	void set_ma8ima_1(int a) { ma8ima_1 = a; }
	int get_ma8ima_1() { return ma8ima_1; }
	void set_ma8ima_2(int b) { ma8ima_2 = b; }
	int get_ma8ima_2() { return ma8ima_2; }
	void set_ma8ima_3(int c) { ma8ima_3 = c; }
	int get_ma8ima_3() { return ma8ima_3; }
	student() {};
	student(float a, float b, float c) : ma8ima_1(a), ma8ima_2(b), ma8ima_3(c) {}

	float average() { return (ma8ima_1 + ma8ima_2 + ma8ima_3) / 3.0; }
} stnts[NO_STUDENT];

int main()
{
	int a, b, c;
	//Βαθμοί πρ΄του μαθήματος
	cout << "dwse ba8mous sto prwto ma8ima" << endl;
	for (int i = 0; i < NO_STUDENT; ++i) {
		cin >> a;
		a = stnts[i].get_ma8ima_1();
	}

	//Βαθμοί δεύτερου μαθήματος
	cout << "dwse ba8mous sto deutero ma8ima" << endl;
	for (int i = 0; i < NO_STUDENT; ++i) {
		cin >> b;
		b = stnts[i].get_ma8ima_2();
	}

	//Βαθμοί τρίτου μαθήματος
	cout << "dwse ba8mous sto trito ma8ima" << endl;
	for (int i = 0; i < NO_STUDENT; ++i) {
		cin >> c;
		c = stnts[i].get_ma8ima_3();
	}

	//Εκτύπωση μαθημάτων φοιτητών
	for (int i = 0; i < NO_STUDENT; ++i) {
		cout << a << '\n';
		cout << b << '\n';
		cout << c << '\n';
	}
0

Αν ο κωδικας σου ειναι αυτό που μας έστειλες, λογικό μου φαίνεται. Δεν αλλάζεις ποτέ τις τιμές των a,b,c όταν τα τυπώνεις, αρα καθε φορά τυπωνεις τα ιδια αποτελέσματα.

0

Δεν υποτίθεται όμως ότι τα a, b, c αλλάζουν εφόσον τους έχω αναθέσει κάθε φορά να λαμβάνουν τιμές stnts[i].get_ma8ima_i(); Επίσης δοκίμασα και το παρακάτω αλλά πάλι το ίδιο βγάζει:

//Εκτύπωση μαθημάτων φοιτητών
	for (int i = 0; i < NO_STUDENT; ++i) {
		cout << stnts[i].get_ma8ima_1() << '\n';
		cout << stnts[i].get_ma8ima_2() << '\n';
		cout << stnts[i].get_ma8ima_3() << '\n';
	}

Τι ακριβώς χάνω σε σκεπτικό που δεν πρέπει και δεν έχω ενσωματώσει;

0

Αν ακολουθήσεις αυτά που σου είπα πριν, θα δουλευει. Η αληθεια ειναι καθε φορα κανεις αλλαγες, τις οποιες δεν ειχα προσεξει. Θα στα ξαναγραψω μια φορα μαζεμενα.

Εχεις μια private μεταβλητη. Αυτο σημαινει οτι ειναι προσβάσιμη μονο απο την ιδια την κλάση, κανεναν αλλο και για κανενα λογο.
Αν θελεις να κανεις αλλαγες στην μεταβλητη, προσθετεις ενα getter και ενα setter οπως εχεις κανει. Ο getter μας επιστρεφει την μεταβλητή και ο setter την αλλάζει.

Τωρα εσυ στο προγραμμα σου, σε καθε επαναληψη εχεις γραψει και κατι διαφορετικο που δεν βγαζει νοημα.

for (int i = 0; i < NO_STUDENT; ++i){
	cin >> a;
   cout << stnts[i].set_ma8ima_1(a);
}

Αυτο είναι λάθος γιατι προσπαθεις να τυπωσεις το αποτελεσμα μια void συναρτησης (δηλαδη το τιποτα), οποτε δεν κανει καν compile.

for (int i = 0; i < NO_STUDENT; ++i) {
	cin >> a;
	a = stnts[i].get_ma8ima_1();
}

Εδω αναθετεις στο a το αποτελεσμα της get_ma8ima_1(), δηλαδη αναθετεις στο a την τιμη της private μεταβλητης, κατι το οποιο δεν εχεις ορισει. Αρα τελικα δεν αλλαζεις ποτε την τιμη της μεταβλητης ma8ima_1.

Αυτό που θέλεις είναι:

int grade;
cin >> grade;
stnts[i].set_Ma8ima_1(grade);

για να θεσεις τιμη στην μεταβλητη του μαθηματος, και

int c;
c = stnts[i].get_Ma8ima_1();
cout << c << '\n';

για να την παρεις και να την τυπωσεις.

0

Τέλεια! Τώρα το έπιασα, τα διόρθωσα και λειτουργεί μια χαρά! Ευχαριστώ και πάλι για όλα!

301 questions

289 answers

288 comments

903 users