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

Καλησπέρα και πάλι. Αρχικά θα ήθελα να ρωτήσω, είναι η ιδέα μου ότι το link της παράδοσης 18/12 είναι το ίδιο με αυτό της παράδοσης 11/12, το οποίο είναι η 10η διάλεξη και όχι η 11η;

Τώρα, σχετικά με την ερώτησή μου επί του κώδικα. Σε προηγούμενη ερώτηση (Error prompt - member inaccessible) αναλύθηκε η χρησιμότητα του setter και του getter για private μέλη κλάσης. Πιο συγκεκριμένα, αφορούσε τον παρακάτω κώδικα:

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

Ωστόσο, μετά από λάθος κατά την γραφή κώδικα με βάση ένα παράδειγμα στο βιβλίο διαπίστωσα ότι, παρά το γεγονός ότι δε χρησιμοποίησα getter, υπήρχε κανονικά πρόσβαση στις private μεταβλητές μέλη απλά και μόνο με το setter, και μάλιστα οι τιμές των μεταβλητών εκτυπώθηκαν κανονικά. Ο λόγος για τον παρακάτω κώδικα:

class kafetiera {
private:
    double kafes{};
    double gala{};
    double zaxari{};
    double nero{};
    double kafedes{};
public:
    bool eparkeia(double z, double k, double n, double g) {
        if (zaxari >= z && kafes >= k && nero >= n && gala >= g)
            return true;
        else
            return false;
    };
    kafetiera() {};
    kafetiera(double z, double k, double n, double g) : kafes(k), gala(g), zaxari(z), nero(n) {};
    void set_ylika(double z, double k, double n, double g) { kafes=k; gala=g; zaxari=z; nero=n; };
    void status() {
        cout << "kafes: " << kafes << ' ' << " Gala: " << gala << " zaxari: " << zaxari << " Nero: " << nero << " Kafedes ws twra: " << kafedes;
    };
    void sketos(double ar);
    void glykos(double ar);
    void metrios(double ar);
}kaf1;

Ήθελα να ρωτήσω συνεπώς, τελικά το getter έχει νόημα χρήσης ή και μόνο το setter φτάνει για τις private μεταβλητές; Και αν έχει, υπό ποιες προϋποθέσεις είναι απαραίτητο;

in progintro by (820 points) | 481 views
0

Δεν είμαι ακριβώς σίγουρος ποια ήταν η συμπεριφορά που περίμενες να δεις. Θέλεις να εξηγήσεις λίγο παραπάνω την ερώτηση σου;

0

Μήπως είναι καλύτερο να κάνεις ξεχωριστή ερώτηση για το πρώτο για να κατηγοριοποιηθεί και διαφορετικά;

0

Ευχαριστώ για το σχόλιο. Να πω την αλήθεια, αυτό που περίμενα (μάλλον εσφαλμένα) να δω είναι όταν στη main βάζω πχ

int main(){
    kaf1.set_ylika(1000, 2000, 10000, 1000);
    kaf1.status(); //Έλεγχος υλικών
    kaf1.glykos(2); //κατασκευή γλυκού
    kaf1.status(); //Έλεγχος υλικών
    kaf1.sketos(1); //κατασκευή σκέτου
    kaf1.status(); //Έλεγχος υλικών 
return 0;
}

αυτό λογικά να έχει πρόσβαση για να θέσει στις private μεταβλητές τις τιμές, ωστόσο να μη μπορεί να τις τυπώσει αφού θα λείπει ο getter ο οποίος θα δίνει πρόσβαση για επιστροφή των τιμών με σκοπό να μπορούν να χρησιμοποιηθούν για εκτύπωση ή για ότι άλλο.

0

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

1 Answer

+1 vote

Καταρχάς θα πρότεινα να διαβάσεις αυτό γιατί καλό το trial and error, αλλά κάποια πράγματα πρέπει να τα δείς πιο συστηματικά.

Από το παραπάνω άρθρο:

The class members declared as private can be accessed only by the
member functions inside the class. They are not allowed to be accessed
directly by any object or function outside the class.

Άρα συμπεραίνουμε ότι, από την main πχ, δεν μπορείς να κάνεις κατευθείαν access (πχ να τυπώσεις) τα private μέλη μιας κλάσης (πχ kaf1.kafes), αλλά μπορείς να τα κάνεις access από άλλα μέλη της ίδιας κλάσης (όπως κάνεις στην kafetiera::status()).

Οι seters/geters επομένως είναι χρήσιμοι όταν θες να θέσεις/πάρεις τα private μέλη μιας κλάσης σε συναρτήσεις όπως η main που δεν έχουν απευθείας πρόσβαση.


Edit:

Παρακάτω φαίνονται λάθος και σωστοί τρόποι να θέσεις/ διαβάσεις μια private μεταβλητή εκτός κλάσης.
Τα commented κομμάτια του κώδικα θα προκαλέσουν λάθος μεταγλώττισης αν γίνουν uncomment και άρα είναι λάθος τρόποι να κάνεις το αντίστοιχο task.
Tονίζω ότι η ύπαρξη ή όχι setters και getters δεν θα αλλάξει τη συμπεριφορά των commented (λάθος) κομματιών. Αν γίνουν uncomment θα προκαλέσουν σφάλμα.

#include<iostream>

class A {
private:
 int x;
public:
    void set_x(int i){
        x = i;
    }
    int get_x(){
        return x;
    }
    A():x(0){}
}


int main(){
    class A a;
    
    int i; 
    // a.x = 2;    // ERROR!!! (A::x is private)
    
    a.set_x(2);    // CORRECT
    
    // i = a.x;    // ERROR!!! (A::x is private)
    
    i = get_x();   // CORRECT
    std::cout<<i<<std::endl; // prints 2.
}
by (1.1k points)
edited by
0

Ναι τα έχω διαβάσει τα θεωρητικά περί private protected και public, απλά προσπαθώ να το κατανοήσω πρακτικά πως αυτό εφαρμόζεται στην πράξη. Άρα, εάν καταλαβαίνω καλά, ισχύει το εξής:

Στη main δε μπορώ να έχω κατευθείαν πρόσβαση στα private μέλη (πχ. kaf1.kafes) όμως μπορώ εφόσον έχω χρησιμοποιήσει έναν setter και έχω θέσει τιμές στις μεταβλητές, αυτές να τις χρησιμοποιήσω μέσω συνάρτησης της ίδιας κλάσης (πχ. status ή glykos ή sketos κλπ.).

Ωστόσο, αν όμως θέλω να έχω πρόσβαση κατευθείαν στις private μεταβλητές μέσω main, χωρίς να παρεμβάλεται συνάρτηση της κλάσης, τότε εκτός απο τον setter για να τεθούν οι τιμές στις μεταβλητές πρέπει να βάλω και τον getter ώστε αυτός να δώσει return των μεταβλητών στη main μετά απο πρόσβαση στις private μεταβλητές που αλλιώς δε θα γινόταν.

Το έχω προσεγγίσει σωστά;

0

Γενικά σωστά αλλά να κάνω point out ένα - δυο πραγματάκια:

Στη main δε μπορώ να έχω κατευθείαν πρόσβαση στα private μέλη

Σωστά.

όμως μπορώ εφόσον έχω χρησιμοποιήσει έναν setter και έχω θέσει τιμές
στις μεταβλητές, αυτές να τις χρησιμοποιήσω μέσω συνάρτησης της ίδιας
κλάσης

Μπορείς μέσω public συνάρτησης της κλάσης να κάνεις ενέργειες πάνω στα private μέλη. Το ότι έχεις χρησιμοποιήσει setter είναι άσχετο (παρ' ότι πιθανό).
Όταν η main καλεί μια συνάρτηση ενδιαφέρεται μόνο για το αν μπορεί να κάνει access στη συνάρτηση αυτή· δεν ενδιαφέρεται για τον κώδικα που βρίσκεται μέσα στη συνάρτηση.

αν όμως θέλω να έχω πρόσβαση κατευθείαν στις private μεταβλητές μέσω main

Απευθείας πρόσβαση δεν μπορείς να έχεις σε private μεταβλητές. Το πιο κοντινό όμως που μπορείς να έχεις σε απευθείας πρόσβαση είναι να έχεις μια public μέθοδο για να παίρνεις την τιμή της μεταβλητής και μια public μέθοδο για να την θέτεις. Τις μεθόδους που κάνουν αυτήν τη δουλειά τις λέμε getters και setters αντίστοιχα.

Σημειώνω ότι ένας getter/setter δεν είναι construct της c++. Για τη c++ είναι απλώς μια ακόμα public μέθοδος. Απλά επειδή συχνά φτιάχνουμε μεθόδους που κάνουν αυτό το πράγμα τους έχουμε δώσει (εμείς οι προγραμματιστές) όνομα.

0

Ευχαριστώ για την απάντηση. Απ' ότι διαπίστωσα πάντως στον προηγούμενο κώδικα δε μπορούσα να έχω access σε private μέλη μέσω public συνάρτησης χωρίς setter.

Σχετικά με την απευθείας πρόσβαση, δε θα μπορούσα να γράψω στη main πχ ( kaf1.kafes= ....; ) και να θέσω την τιμή που θέλω;Σε αυτή την περίπτωση, αν απλά θέσω την τιμή στη μεταβλητή private αυτή, θα χρειαστώ μόνο setter ή και getter;

Τώρα σχετικά με τον getter. Οκ, έτσι το γεγονός ότι στον κώδικα αυτό δε χρησιμοποίησα getter και ο κώδικας έτρεξε μια χαρά είναι διότι οι public συναρτήσεις της κλάσης που στην main δήλωσα είναι τύπου void και άρα δεν επιστρέφουν τιμή, και άρα αφού δεν επιστρέφουν τιμή τότε αρκεί να έχω μόνο setter ώστε να δουλέψει η συνάρτηση και ο κώδικας. Ενώ αν δεν ήταν τύπου void οι συναρτήσεις και επέστρεφαν τιμή τότε θα χρειαζομουν και getter για να μπορέσει να επιστρέψει την τιμή;

Παρεπιπτόντως καλές γιορτές εύχομαι!

0

Σχετικά με την απευθείας πρόσβαση, δε θα μπορούσα να γράψω στη main πχ ( kaf1.kafes= ....; ) και να θέσω την τιμή που θέλω;

Αν το kafes είναι private μέλος τότε η έκφραση kaf1.kafes στη main θα προκαλέσει compiling error (κάτι της μορφής: ‘double kafetiera::kafes’ is private within this context).

το γεγονός ότι στον κώδικα αυτό δε χρησιμοποίησα getter και ο κώδικας έτρεξε μια χαρά

Εδώ είτε δεν το εκφράζεις καλά, είτε δεν το έχεις καταλάβει καλά. Ένας κώδικας που δεν έχει errors τρέχει. Δεν υπάρχει κάποιο error που να σημαίνει "δεν έχεις βάλει getter".

Αυτό που μπορεί να εννοείς είναι να προσπαθήσεις να πάρεις απευθείας την τιμή μιας private μεταβλητής στη main (πχ x=kaf1.kafes). Κάτι τέτοιο θα προκαλέσει error ανεξαρτήτως του αν έχεις ορίσει setter / getter.

Θα προσθέσω ένα παράδειγμα στην απάντηση.

Καλές γιορτές και σε σένα!

0

<<Εδώ είτε δεν το εκφράζεις καλά, είτε δεν το έχεις καταλάβει καλά. Ένας κώδικας που δεν έχει errors τρέχει. Δεν υπάρχει κάποιο error που να σημαίνει "δεν έχεις βάλει getter".>>

Μισό λίγο. Στον παρακάτω κώδικα, ο οποίος και ήταν απορία προηγούμενου θέματος, ο κώδικάς μου δεν έτρεχε και έβγαζε error λόγω πρόσβασης γιατί δεν είχα βάλει getter

// 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()
{
	
	//Βαθμοί πρώτου μαθήματος
	cout << "dwse ba8mous sto prwto ma8ima" << endl;
	for (int i = 0; i < NO_STUDENT; ++i) {
		int grade; 
		cin >> grade;
		stnts[i].set_ma8ima_1(grade); 
	}

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

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

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

Δεν προσπαθούσα να πάρω κάποια τιμή αλλά προσπαθούσα να τυπώσω απλά την τιμή που είχα βάλει με το setter. Αυτό μου έβγαζε error.

Η απορία μου δηλαδή εμένα ουσιαστικά είναι, γιατί στο παράδειγμα αυτο που έβαλα τώρα με τους μαθητές χρειάζεται ο getter και δε μου δούλευε χωρίς αυτόν, ενώ στο παράδειγμα του θέματος που άνοιξα σήμερα με την καφετιέρα ο κώδικας δούλεψε κανονικά μόνο με το setter; Παίζει ρόλο ότι οι συναρτήσεις στην καφετιέρα είναι void και δεν επιστρέφουν τιμές ενώ στους μαθητές ήταν int, ή είναι κάποιος άλλος λόγος; Ναι η αλήθεια είναι ότι ένα παράδειγμα θα ήταν μια βοήθεια παραπάνω.

Ευχαριστώ και πάλι

0

Έχω προσθέσει το παράδειγμα στην αρχική απάντηση. Τα υπόλοιπα θα στα στείλω σε pm, γιατί πιστεύω έχει απαντηθεί αρκούντως η ερώτηση για το community.

301 questions

289 answers

288 comments

903 users