web-dev-qa-db-fra.com

passage d'objet par référence en C ++

La manière habituelle de passer une variable par référence en C++ (également en C) est la suivante:

void _someFunction(dataType *name){ // dataType e.g int,char,float etc.
/****
definition
*/
}

int main(){
    dataType v;
    _somefunction(&v);  //address of variable v being passed
    return 0;
}

Mais à ma grande surprise, j’ai remarqué que quand passage d’un objet à l’autre le nom de l’objet lui-même sert à cela (no & symbole requis) et que lors de la déclaration/définition de la fonction n ° * Le symbole est requis avant l'argument. L'exemple suivant devrait préciser:

// this
#include <iostream>
using namespace std;

class CDummy {
  public:
    int isitme (CDummy& param);     //why not (CDummy* param);
};

int CDummy::isitme (CDummy& param)
{
  if (&param == this) return true;
  else return false;
}

int main () {
  CDummy a;
  CDummy* b = &a;
  if ( b->isitme(a) )               //why not isitme(&a)
    cout << "yes, &a is b";
  return 0;
}

J'ai du mal à comprendre pourquoi ce traitement spécial est fait en classe. Même les structures qui ressemblent presque à une classe ne sont pas utilisées de cette façon. Le nom de l'objet est-il traité comme une adresse comme dans le cas des tableaux?

26
KNU

Ce qui semble vous dérouter, c’est que les fonctions déclarées passer-par-référence (à l’aide de la commande &) ne sont pas appelés avec des adresses réelles, c.-à-d. &a.

La réponse simple est que la déclaration d'une fonction comme passe par référence:

void foo(int& x);

c'est tout ce dont nous avons besoin. Il est ensuite transmis automatiquement par référence.

Vous appelez maintenant cette fonction comme suit:

int y = 5;
foo(y);

et y seront passés par référence.

Vous pouvez aussi le faire comme ceci (mais pourquoi le feriez-vous? Le mantra est le suivant: tilisez des références lorsque cela est possible, des pointeurs en cas de besoin):

#include <iostream>
using namespace std;

class CDummy {
public:
    int isitme (CDummy* param);
};


int CDummy::isitme (CDummy* param)
{
    if (param == this) return true;
    else return false;
}

int main () {
    CDummy a;
    CDummy* b = &a;             // assigning address of a to b
    if ( b->isitme(&a) )        // Called with &a (address of a) instead of a
        cout << "yes, &a is b";
    return 0;
}

Sortie:

yes, &a is b
55
keyser

Une référence est vraiment un pointeur avec suffisamment de sucre pour lui donner un goût agréable…;)

Mais il utilise également une syntaxe différente pour les pointeurs, ce qui rend l'utilisation des références un peu plus facile que celle des pointeurs. Pour cette raison, nous n'avons pas besoin de & lorsque vous appelez la fonction qui prend le pointeur - le compilateur s’occupe de cela pour vous. Et vous n'avez pas besoin de * pour obtenir le contenu d'une référence.

Appeler une référence un alias est une description assez précise - c'est "un autre nom pour la même chose". Donc, lorsque a est passé en tant que référence, nous transmettons vraiment a, pas une copie de a - cela se fait (en interne) en passant l'adresse de a, mais vous n'avez pas à vous soucier de la façon dont cela fonctionne [à moins d'écrire votre propre compilateur, mais il y a beaucoup d'autres choses amusantes que vous devez savoir lorsque vous écrivez votre propre compilateur. besoin de s'inquiéter quand vous programmez juste].

Notez que les références fonctionnent de la même manière pour int ou un type class.

12
Mats Petersson

Passer par référence dans le cas ci-dessus est juste un alias pour l'objet réel.

Vous ferez référence à l'objet réel avec un nom différent.

references offre de nombreux avantages par rapport à pointer references.

2
Uchia Itachi

Ok, eh bien, il semblerait que vous confondiez passage par référence et passage par valeur. En outre, C et C++ sont des langages différents. C ne prend pas en charge la référence par référence.

Voici deux exemples C++ de pass par valeur:

// ex.1
int add(int a, int b)
{
    return a + b;
}

// ex.2
void add(int a, int b, int *result)
{
    *result = a + b;
}

void main()
{
    int result = 0;

    // ex.1
    result = add(2,2); // result will be 4 after call

    // ex.2
    add(2,3,&result); // result will be 5 after call
}

Lorsque ex.1 est appelé, les constantes 2 et 2 sont passés à la fonction en en créant des copies locales sur la pile. Lorsque la fonction revient, la pile est retirée et tout ce qui est passé à la fonction sur la pile est effectivement parti.

La même chose se passe dans ex.2 , sauf que cette fois, un pointeur sur une variable int est également passé sur la pile. La fonction utilise ce pointeur (qui est simplement une adresse mémoire) pour déréférencer et modifier la valeur à cette adresse mémoire afin de "renvoyer" le résultat. Comme la fonction a besoin d’une adresse mémoire en tant que paramètre, nous devons en fournir une, ce que nous faisons en utilisant le & Opérateur "address-of" sur la variable result.

Voici deux exemples C++ de pass-by-reference:

// ex.3
int add(int &a, int &b)
{
    return a+b;
}

// ex.4
void add(int &a, int &b, int &result)
{
    result = a + b;
}

void main()
{
    int result = 0;

    // ex.3
    result = add(2,2); // result = 2 after call
    // ex.4
    add(2,3,result); // result = 5 after call
}

Le résultat final de ces deux fonctions est identique à celui des deux premiers exemples, mais la différence réside dans la façon dont elles sont appelées et dans la façon dont le compilateur les gère.

Tout d’abord, expliquons comment fonctionne la procédure de référence. Pass-by-reference, généralement, l’implémentation du compilateur utilisera une variable "pointeur" dans l’exécutable final afin d’accéder à la variable référencée (ou semble être le consensus), mais cela ne doit pas nécessairement être vrai. Techniquement, le compilateur peut simplement substituer directement l'adresse mémoire de la variable référencée, et je suppose que cela est plus vrai qu'on ne le pense généralement. Ainsi, lorsque vous utilisez une référence, vous obtiendrez un exécutable plus efficace, même légèrement.

Ensuite, évidemment, la manière dont une fonction est appelée lorsqu’on utilise passe-par-référence n’est pas différente de celle-ci, et l’effet est que vous avez un accès direct aux variables d’origine de la fonction. Cela a pour résultat une encapsulation en masquant les détails d'implémentation de l'appelant. L'inconvénient est que vous ne pouvez pas modifier les paramètres passés sans modifier également les variables d'origine en dehors de la fonction. Dans les fonctions pour lesquelles l'amélioration des performances ne nécessite pas de copier des objets volumineux, mais que vous ne souhaitez pas modifier l'objet d'origine, préfixez les paramètres de référence avec const.

Enfin, vous ne pouvez pas modifier une référence après sa création, contrairement à une variable de pointeur, et celles-ci doivent être initialisées lors de la création.

J'espère que j'ai tout couvert et que tout était compréhensible.

1
SeanRamey

Une chose que je dois ajouter, c'est qu'il n'y a pas de référence en C.

Deuxièmement, il s'agit de la convention de syntaxe de langage. & - est un opérateur d’adresse mais c’est aussi une référence - tout dépend du cas américain

S'il y avait un mot-clé "référence" au lieu de & vous pourriez écrire

int CDummy::isitme (reference CDummy param)

mais c’est du C++ et nous devrions en accepter les avantages et les inconvénients ...

0
LukeCodeBaker