C ++: Passage d’objects par valeur à une fonction membre de la même classe

Je suis débutant en C ++ et je viens tout juste de commencer à apprendre la POO. Dans le programme suivant, j’ai ajouté des objects des mêmes classes et affiché le résultat. Cependant, je ne suis pas capable de comprendre le fait que si je passe les objects à la fonction par valeur, comment le changement est-il reflété dans la fonction appelante? La fonction addNumbers() attend deux objects de la classe Complex et l’object utilisé pour appeler la fonction ( c3.addNumbers(c1, c2) ) est implicitement transmis à la fonction, mais quelles sont les valeurs de c3.real et c3.imaginary affecté dans la fonction appelante puisque addNumbers() n’a pas access à leur “emplacement” dans la mémoire. Toute aide serait appréciée!

Merci d’avance!

 class complex { private: int real; int imaginary; public: /* Using member initializers to assign values to members */ complex() : real(0) , imaginary(0) {} void readData(int x, int y); void printData(); void addNumbers(complex, complex); }; void complex::readData(int x, int y) { real = x; imaginary = y; } void complex::printData() { cout << real << "+" << imaginary << "i" << endl; } void complex::addNumbers(complex c1, complex c2) { real = c1.real + c2.real; imaginary = c1.imaginary + c2.imaginary; } int main(void) { complex c1, c2, c3; c1.readData(-5,17); c2.readData(11,7); c3.addNumbers(c1,c2); c3.printData(); return 0; } 

J’ai fait quelques commentaires dans votre code d’origine pour expliquer pourquoi réel et imaginaire sont affectés ci-dessous. (Cherchez // MABVT)

De plus, je vais vous donner un autre exemple utile pour progresser davantage!

LA REVUE

 class complex { private: int real; int imaginary; public: /* Using member initializers to assign values to members */ complex() : real(0) , imaginary(0) {} void readData(int x, int y); void printData(); // MABVT: You provide two complex numbers which you want to add // together! void addNumbers(complex, complex); }; void complex::readData(int x, int y) { real = x; imaginary = y; } void complex::printData() { cout << real << "+" << imaginary << "i" << endl; } void complex::addNumbers(complex c1, complex c2) { // MABVT: Use c1.component and c2.component, add them up and store them // in this class' instance. real = c1.real + c2.real; imaginary = c1.imaginary + c2.imaginary; // MABVT: c3.real and c3.imaginary are affected at this exact location // since you overwrite the values with the addition-results. // Since the function addNumbers(complex, complex) is invoked // on the complex instance 'c3', real and imaginary of c3 are // known in this context, and consequently you can use them. // // To attach to your statement that the c3 instance's pointer is // implicitly passed: // Yes it is passed as the first parameter invisibly as // 'complex* this' // // So you could also write: // this->real = c1.real + c2.real; (see the use of this?) } int main(void) { complex c1, c2, c3; c1.readData(-5,17); c2.readData(11,7); c3.addNumbers(c1,c2); c3.printData(); return 0; } 

ALTERNATIVE

 // Example program #include  #include  class Complex { // Give class names capital first letter private: int m_real; // Just a recommendation: I'd like to be able to distinguish parameter for member in the identifier already! int m_imaginary; // Just a recommendation: I'd like to be able to distinguish parameter for member in the identifier already! public: /* Using member initializers to assign values to members */ inline Complex() // Inline it, if you define this class in a header and reuse it multiple times... : m_real(0) , m_imaginary(0) {} // Provide initializing constructor to be able to construct // a complex number quickly. Replaces your readData(...); inline Complex( int inRealPart, int inImaginaryPart) : m_real(inRealPart) , m_imaginary(inImaginaryPart) {} // Getters to read the values inline int real() const { return m_real; } inline int imaginary() const { return m_imaginary; } void printData(); // Local assignment-add operator to add another complex // to this specific instance of complex and modify the internal // values. Basically what you did as the second part of addNumbers. Complex& operator+=(const Complex& r); }; void Complex::printData() { std::cout << m_real << "+" << m_imaginary << "i" << std::endl; } // Member add-assign operator definition adding this instance and another instance 'r' by adding up the values and storing them in the instance this operator is called on. Complex& Complex::operator +=(const Complex& r) { std::cout << "Local" << std::endl; this->m_real += r.real(); this->m_imaginary += r.imaginary(); return *this; } // Static global operator+ definition, taking two values and creating a // third, NEW one initialized with the results. // This was the first part of addNumbers static Complex operator+(const Complex& l, const Complex& r) { std::cout << "Static Global" << std::endl; return Complex( (l.real() + r.real()), (l.imaginary() + r.imaginary()) ); } int main(void) { // Same as before Complex c1(-5, 17); Complex c2(11, 7); Complex c3(1, 2); // Test output c1.printData(); c2.printData(); c3.printData(); std::cout << std::endl; Complex c3 = (c1 + c2); // Calls static global and c3 is overwritten with the result. Exactly like your addNumbers call c1 += c2; // instance local, will change c1's internal values ( see print out below ) Complex c5 = ::operator+(c1, c2); // Static global, c5 is initialized with the result. Exactly like your addNumbers call std::cout << std::endl; c1.printData(); c2.printData(); c3.printData(); c5.printData(); return 0; } 

Cela devrait être assez pour vous en tant que débutant.

Quelques explications

Surcharges statiques d'opérateurs globaux et locaux

Lecture sur le sujet: http://fr.cppreference.com/w/cpp/language/operators

Tous les opérateurs que vous utilisez (+, -, *, /,%, + =, - =, ...) ne sont que des fonctions prédéfinies pour les types primitifs et fournies par libstd pour les types STD.

Vous pouvez cependant les remplacer / les définir.

Je l'ai fait de deux manières:

Opérateur global statique +:

Accepte deux instances complexes arbitraires et ajoute leurs composants. Enfin, une instance NEW est créée et initialisée avec les résultats.

Fondamentalement, il s’agit simplement d’une fonction statique, qui est liée à "+" par le compilateur.

Et:

Opérateur membre local + =:

Accepte une autre instance de Complex et ajoute ses valeurs de composant aux valeurs de composant de l'instance sur laquelle l'opérateur est appelé: `l + = r -> Appelé sur l, dont les valeurs seront modifiées en ajoutant les valeurs de r '

Tous les opérateurs d'opérations (+ =, - =, * =, / =, etc ...) doivent être définis dans la classe et ne peuvent être ni globaux ni statiques.

type const &

Lecture avec beaucoup plus d’informations sur const: https://www.cprogramming.com/tutorial/const_correctness.html

La référence de const aux instances de tout type assurera deux choses pour vous:

  1. & : Vous ne faites que copier l'adresse, mais de cette façon, vous pourriez modifier toutes les valeurs publiques ou appeler la plupart des fonctions.
  2. const : l'instance n'est pas modifiable et rien ne peut être changé

En combinaison, cela signifie: vous n'êtes pas obligé de copier l'instance (passe-par-valeur), mais de ne fournir que la référence d'adresse (passe-par-référence). Généralement, cela améliore les performances, en particulier lorsque vous transmettez des objects volumineux et complexes.

Lorsque vous appelez c3.addNumbers(c1, c2)) , addNumbers reçoit implicitement le pointeur sur c3 non une copie de c3 . Ce pointeur peut être utilisé explicitement avec le mot this clé this .

Donc, votre fonction peut être réécrite comme ceci:

 void complex::addNumbers(complex c1, complex c2) { this->real = c1.real + c2.real; this->imaginary = c1.imaginary + c2.imaginary; } 

ce qui est ssortingctement équivalent à votre fonction addNumbers originale.

En d’autres termes: chaque fois que vous utilisez un membre de classe dans une fonction membre, un this-> implicite est ajouté à ce membre; Ainsi, si member est un membre de la classe, member est toujours équivalent à this->member dans une fonction membre de la classe.

L’imaginaire et le réel sont des propriétés privées, mais ils sont accessibles via la fonction membre (également appelée méthode de l’object). Lorsque l’instruction c3.addNumbers (c1, c2) est exécutée, elle équivaut aux deux instructions suivantes:

c3.real = c1.real + c2.real;

c3.imaginary = c1.imaginary + c2.imaginary

Si nous pouvons accéder à c3.real et à c3.imaginary, c’est parce que la fonction addNymbers () est membre de la classe Complex.