J'apprends le C++ et j'ai créé deux applications simples Hello World. Dans les deux cas, j'utilise la surcharge de l'opérateur, mais voici le problème. Sur le premier, je peux fournir deux arguments à l'opérateur de surcharge, et c'est bien.
Entête:
enum Element {a,b,c,d,e};
Element operator + (Element x, Element y);
//more overloads for -, *, / here
La source:
Element operator + (Element x, Element y) {
return ArrayOfElements[x][y];
}
Mais dans ma deuxième application (calculatrice simple et complexe), cette méthode ne fonctionnait pas. Après avoir googlé et compris pourquoi, je me retrouve avec ce code:
Entête:
struct Complex {
double Re;
double Im;
Complex (double R, double I) : Re(R), Im(I) { }
Complex operator + (Complex &Number);
//more overloads
};
La source:
Complex Complex::operator + (Complex &Number)
{
Complex tmp = Complex(0, 0);
tmp.Re = Re + Number.Re;
tmp.Im = Im + Number.Im;
return tmp;
}
Cela fonctionne maintenant, mais je veux savoir, pourquoi dans le premier morceau de code on m'a permis de mettre deux arguments dans la surcharge operator
, mais avec le second, l'erreur suivante a été donnée?
complex.cpp:5:51: error: 'Complex Complex::operator+(Complex, Complex)' must take either zero or one argument
C'est la même chose que j'utilise des cours ou non. J'ai cherché dans de nombreux documents et la deuxième méthode semble être plus correcte. Peut-être est-ce à cause de différents types d'arguments?
Les deux sources compilées avec les paramètres -Wall -pedantic
à l'aide de g++
utilisent toutes les deux la même bibliothèque.
Supposons que vous ayez une classe comme celle-ci:
class Element {
public:
Element(int value) : value(value) {}
int getValue() const { return value; }
private:
int value;
};
Il existe quatre façons de définir un opérateur binaire tel que +
.
En tant que fonction libre avec accès aux seuls membres public
de la classe:
// Left operand is 'a'; right is 'b'.
Element operator+(const Element& a, const Element& b) {
return Element(a.getValue() + b.getValue());
}
e1 + e2 == operator+(e1, e2)
En tant que fonction membre, avec accès à tous les membres de la classe:
class Element {
public:
// Left operand is 'this'; right is 'other'.
Element operator+(const Element& other) const {
return Element(value + other.value);
}
// ...
};
e1 + e2 == e1.operator+(e2)
En tant que fonction friend
, avec un accès à tous les membres de la classe:
class Element {
public:
// Left operand is 'a'; right is 'b'.
friend Element operator+(const Element& a, const Element& b) {
return a.value + b.value;
}
// ...
};
e1 + e2 == operator+(e1, e2)
En tant que fonction friend
définie en dehors du corps de la classe - comportement identique à # 3:
class Element {
public:
friend Element operator+(const Element&, const Element&);
// ...
};
Element operator+(const Element& a, const Element& b) {
return a.value + b.value;
}
e1 + e2 == operator+(e1, e2)
Puisque + est un opérateur binaire, si vous le surchargez dans une structure/classe, vous ne pouvez fournir qu'un seul opérande supplémentaire, car le premier opérande est implicitement l'objet appelant. C'est pourquoi, dans le premier cas, vous avez deux paramètres car ils sortent du cadre de votre classe/structure, alors que dans le second cas, ils ont été surchargés en tant que fonction membre.
Si vous préférez que operator+
prenne les deux opérandes en tant qu'arguments explicites, vous devez le définir comme une fonction libre (c'est-à-dire non membre):
class Complex {
friend Complex operator+(const Complex& lhs, const Complex& rhs);
}
Complex operator+(const Complex& lhs, const Complex& rhs) {
...
}
Vous devez utiliser ce formulaire si l'opérande de gauche est d'un type primitif ou d'une classe que vous ne contrôlez pas (et ne peut donc pas ajouter de fonction membre).
Si la fonction surchargée est une fonction membre de la classe, nous ne transmettons qu'un argument et il existe un paramètre caché ( this pointeur) qui pointe vers un autre objet requis pour effectuer une opération binaire comme '+'. this le pointeur pointe sur l'un des opérandes et appelle la fonction surchargée; tandis que l’autre opérande est passé sous forme d’argument ..__ Exemple:
class ExampleClass
{
public:
int x;
//a this pointer will be passed to this function
ExampleClass& operator+(const ExampleClass& o){ return x+o.x; }
};
ExampleClass obj1, obj2, obj;
obj = obj1 + obj2; //the overloaded function is called as obj1.operator+(obj2) internally
//this pointer is passed to the function
Lorsque la fonction surchargée n'est pas une fonction membre (une fonction libre ou une fonction amie), le pointeur this n'est pas fourni pour la fonction surchargée. Dans ce cas, le compilateur attend deux arguments de la fonction qui sont utilisés comme opérandes.
class ExampleClass
{
public:
int x;
//this pointer will not be passed to this function
friend ExampleClass& operator+(const ExampleClass& o1, const ExampleClass& o2){ return o1.x+o2.x; }
};
obj = obj1 + obj2; //the overloaded function is called as operator+(obj1, obj2) internally
e1 + e2 == e1.operator + (e2) cela signifie que e1 est un objet et que + est un membre et e2 est une variable. )