Comment passer des objets à des fonctions en C++?

je suis nouveau dans la programmation C++, mais j'ai de l'expérience en Java. J'ai besoin de conseils sur la façon de passer des objets à des fonctions en C++.

ai-je besoin de passer des pointeurs, des références ou des valeurs non-pointer et non-référence? Je me souviens Qu'en Java, il n'y a pas de problèmes de ce genre puisque nous passons juste la variable qui contient une référence aux objets.

ce serait génial si vous pouviez aussi expliquer où utiliser chacune de ces options.

225
demandé sur Rakesh K 2010-01-26 15:08:07

7 réponses

règles empiriques pour C++11:

Pass par la valeur , sauf lorsqu'

  1. vous n'avez pas besoin de la propriété de l'objet et un simple alias de le faire, auquel cas vous passer par là const de référence ,
  2. vous devez muter l'objet ,auquel cas, utiliser passer par un non- const lvalue de référence ,
  3. vous passez des objets de classes dérivées comme classes de base, auquel cas vous devez passer par référence . (Utilisez les règles précédentes pour déterminer si vous devez passer par const référence ou non.)

le passage par l'aiguille n'est pratiquement jamais conseillé. Les paramètres optionnels sont mieux exprimés en boost::optional , et l'alias est fait très bien par référence.

La sémantique des mouvements de

C++11 rend le passage et le retour par valeur beaucoup plus attrayant même pour les objets complexes.


Règles d'or pour C++03:

Passer des arguments par const de référence , sauf lorsqu'

  1. ils doivent être modifié à l'intérieur de la fonction et de tels changements doivent se refléter à l'extérieur, dans ce cas, vous passer par non - const référence
  2. la fonction doit être appelable sans aucun argument, auquel cas vous passez par pointeur, de sorte que les utilisateurs peuvent passer NULL / 0 / nullptr plutôt, appliquer la règle précédente pour déterminer si vous devriez passer par un pointeur à un const argument
  3. ils sont de type intégré, qui peut être passé par copie
  4. "
  5. ils doivent être changés à l'intérieur de la fonction et de tels changements devraient pas être reflétés à l'extérieur, dans ce cas, vous pouvez passer par la copie (une alternative serait de passer selon le règles précédentes et faire une copie à l'intérieur de la fonction)

(ici," pass by value "s'appelle" pass by copy", car passer par la valeur crée toujours une copie en C++03)


il y a plus que cela, mais ces quelques règles de débutant vous mèneront assez loin.

252
répondu sbi 2016-10-31 02:58:41

il y a quelques différences dans les conventions d'appel en C++ et en Java. En C++ il n'y a techniquement que deux conventions: pass-by-value et pass-by-reference, avec une certaine littérature incluant une troisième convention pass-by-pointer (qui est en fait pass-by-value d'un type de pointeur). En plus de cela, vous pouvez ajouter const-ness au type d'argument, améliorant la sémantique.

Passage par référence

de passage la référence signifie que la fonction recevra conceptuellement votre instance objet et non une copie de celle-ci. La référence est conceptuellement un alias de l'objet qui a été utilisé dans le contexte de l'appel, et ne peut pas être nulle. Toutes les opérations effectuées à l'intérieur de la fonction s'appliquent à l'objet à l'extérieur de la fonction. Cette convention N'est pas disponible en Java ou C.

Passage par valeur (et le passage par pointeur)

le compilateur générera une copie de l'objet dans le contexte de l'appel et utiliser cette copie à l'intérieur de la fonction. Toutes les opérations effectuées à l'intérieur de la fonction sont effectuées sur la copie, et non sur l'élément externe. C'est la convention pour les types primitifs en Java.

Une version spéciale de c'est en passant un pointeur (l'adresse de l'objet) dans une fonction. La fonction reçoit le pointeur, et toutes les opérations effectuées sur le pointeur lui-même sont appliqués à la copie (pointeur), d'autre part, les opérations de appliqué au pointeur déréférencé s'appliquera à l'instance de l'objet à cet emplacement de mémoire, de sorte que la fonction peut avoir des effets secondaires. L'effet de l'utilisation de la valeur de passage d'un pointeur vers l'objet permettra à la fonction interne de modifier les valeurs externes, comme avec la référence de passage et permettra également des valeurs optionnelles (passer un pointeur nul).

C'est la convention utilisée en C, une fonction doit modifier une variable externe, et la convention utilisée en Java avec types de référence: la référence est copiée, mais l'objet référencé est le même: les changements à la référence/pointeur ne sont pas visibles en dehors de la fonction, mais les changements à la mémoire pointée le sont.

ajouter const à l'équation

"

en C++, vous pouvez assigner une constante-ness aux objets lors de la définition de variables, de pointeurs et de références à différents niveaux. Vous pouvez déclarer une variable constante, vous pouvez déclarer une référence à un instance constante, et vous pouvez définir tous les pointeurs vers des objets constants, des pointeurs constants vers des objets mutables et des pointeurs constants vers des éléments constants. Inversement, en Java, vous ne pouvez définir qu'un niveau de constante-ness (mot-clé final): celui de la variable (par exemple pour les types primitifs, référence pour les types de référence), mais vous ne pouvez pas définir une référence à un élément immuable (à moins que la classe elle-même ne soit immuable).

c'est largement utilisé dans les conventions d'appel C++. Lorsque les objets sont petits, vous pouvez passer de l'objet par valeur. Le compilateur générera une copie, mais cette copie n'est pas une opération coûteuse. Pour tout autre type, si la fonction ne change pas l'objet, vous pouvez passer une référence à une instance constante (habituellement appelée référence constante) du type. Ceci ne copiera pas l'objet, mais le passera dans la fonction. Mais dans le même temps, le compilateur garantit que l'objet n'est pas modifié à l'intérieur de la fonction.

Règles d'or

Ce sont quelques règles de base à suivre:

  • Préfèrent passer par valeur pour les types primitifs
  • Préfèrent passer par référence avec des références constantes pour d'autres types de
  • si la fonction doit modifier l'argument utiliser pass-by-reference
  • Si l'argument est optionnel, utilisez passage par pointeur (à une constante si la valeur facultative devrait non modifié)

il y a d'autres petites déviations par rapport à ces règles, dont la première concerne la propriété d'un objet. Lorsqu'un objet est affecté dynamiquement avec new, il doit être affecté avec delete (ou ses versions []). L'objet ou la fonction qui est responsable de la destruction de l'objet est considéré comme le propriétaire de la ressource. Lorsqu'un objet alloué dynamiquement est créé dans un morceau de code, mais la propriété est transférée à un élément différent, il est généralement fait avec pass-by-pointer sémantique, ou si possible avec des pointeurs intelligents.

note latérale

il est important d'insister sur l'importance de la différence entre les références C++ et Java. En C++ références sont conceptuellement l'instance de l'objet, pas un accesseur. L'exemple le plus simple est la mise en œuvre d'une fonction de swap:

// C++
class Type; // defined somewhere before, with the appropriate operations
void swap( Type & a, Type & b ) {
   Type tmp = a;
   a = b;
   b = tmp;
}
int main() {
   Type a, b;
   Type old_a = a, old_b = b;
   swap( a, b );
   assert( a == old_b );
   assert( b == old_a ); 
}

la fonction de swap ci-dessus change ses deux arguments par l'utilisation de références. Le code le plus proche en Java:

public class C {
   // ...
   public static void swap( C a, C b ) {
      C tmp = a;
      a = b;
      b = tmp;
   }
   public static void main( String args[] ) {
      C a = new C();
      C b = new C();
      C old_a = a;
      C old_b = b;
      swap( a, b ); 
      // a and b remain unchanged a==old_a, and b==old_b
   }
}

la version Java du code modifiera les copies des références en interne, mais ne modifiera pas les objets réels en externe. Les références Java sont des pointeurs C sans arithmétique de pointeur qui sont passés par la valeur dans les fonctions.

102
répondu David Rodríguez - dribeas 2010-01-26 14:59:05

Il y a plusieurs cas à considérer.

paramètre modifié (paramètres" out "et" in/out")

void modifies(T &param);
// vs
void modifies(T *param);

ce cas est principalement une affaire de style: voulez-vous que le code ressemble à appel(obj) ou appel(&obj) ? Cependant, il y a deux points où la différence importe: le cas optionnel, ci-dessous, et vous voulez utiliser une référence lors de la surcharge des opérateurs.

...et facultatif

void modifies(T *param=0);  // default value optional, too
// vs
void modifies();
void modifies(T &param);

paramètre non modifié

void uses(T const &param);
// vs
void uses(T param);

C'est le cas intéressant. La règle de base est "pas cher à copier" les types sont passés par valeur - ce sont généralement de petits types (mais pas toujours) - tandis que d'autres sont passés par const ref. Cependant, si vous avez besoin de faire une copie dans votre fonction indépendamment, vous devrait passer par la valeur . (Oui, cela expose un peu de détails de mise en œuvre. C est le C++. )

...et facultatif

void uses(T const *param=0);  // default value optional, too
// vs
void uses();
void uses(T const &param);  // or optional(T param)

il y a la moindre différence ici entre toutes les situations, alors choisissez celle qui vous facilite la vie.

Const en valeur est un détail d'implémentation

void f(T);
void f(T const);

ces déclarations sont en fait la même fonction exacte! en passant par la valeur, const est purement un détail de mise en œuvre. Essayez:

void f(int);
void f(int const) { /* implements above function, not an overload */ }

typedef void NC(int);       // typedefing function types
typedef void C(int const);

NC *nc = &f;  // nc is a function pointer
C *c = nc;    // C and NC are identical types
22
répondu 2010-10-19 15:00:46

valeur de transfert:

void func (vector v)

passer des variables en valeur lorsque la fonction doit être complètement isolée de l'environnement, c'est-à-dire empêcher la fonction de modifier la variable d'origine ainsi que d'autres threads de modifier sa valeur pendant que la fonction est exécutée.

l'inconvénient est les cycles CPU et la mémoire supplémentaire dépensée pour copier l'objet.

Passer par const référence:

void func (const vector & v);

cette forme émule le comportement pass-by-value tout en enlevant la copie aérienne. La fonction obtient l'accès en lecture à l'objet d'origine, mais ne peut pas modifier sa valeur.

l'inconvénient est la sécurité du thread: tout changement apporté à l'objet original par un autre thread apparaîtra à l'intérieur de la fonction pendant qu'elle est encore en cours d'exécution.

Passer par des non-const référence:

void func (vector & v)

utilisez ceci lorsque la fonction doit réécrivez une certaine valeur à la variable, qui sera finalement utilisé par l'appelant.

tout comme le cas de référence de const, ce n'est pas sans fil.

Passage par pointeur const:

void func (const vector * vp);

fonctionnellement identique à pass by const-reference sauf pour la syntaxe différente, plus le fait que la fonction d'appel peut passer le pointeur NULL pour indiquer qu'elle n'a pas de données valides à passer.

pas sûr du fil.

Passer par des non-const pointeur:

void func (vector * vp);

similaire à la référence non-const. L'appelant définit généralement la variable à NULL lorsque la fonction n'est pas censée écrire une valeur. Cette convention est observée dans de nombreux API glibc. Exemple:

void func (string * str, /* ... */) {
    if (str != NULL) {
        *str = some_value; // assign to *str only if it's non-null
    }
}

comme tous les passer par référence/pointeur, pas Fil sûre.

15
répondu nav 2015-05-17 18:08:43

puisque personne n'a mentionné que j'ajoute dessus, quand vous passez un objet à une fonction en c++ le constructeur de copie par défaut de l'objet est appelé si vous n'en avez pas un qui crée un clone de l'objet et le passe ensuite à la méthode, donc quand vous changez les valeurs de l'objet qui réfléchiront sur la copie de l'objet au lieu de l'objet original, c'est le problème en c++, donc si vous faites tous les attributs de classe pour être des pointeurs, ensuite, les constructeurs copient les adresses des les attributs de pointeur, donc quand la méthode invocations sur l'objet qui manipule les valeurs stockées dans les adresses d'attributs de pointeur, les changements reflètent également dans l'objet original qui est passé comme un paramètre, de sorte que cela peut se comporter même un Java, mais n'oubliez pas que tous vos attributs de classe doit être des pointeurs, aussi vous devez changer les valeurs des pointeurs, sera très clair avec l'explication de code.

Class CPlusPlusJavaFunctionality {
    public:
       CPlusPlusJavaFunctionality(){
         attribute = new int;
         *attribute = value;
       }

       void setValue(int value){
           *attribute = value;
       }

       void getValue(){
          return *attribute;
       }

       ~ CPlusPlusJavaFuncitonality(){
          delete(attribute);
       }

    private:
       int *attribute;
}

void changeObjectAttribute(CPlusPlusJavaFunctionality obj, int value){
   int* prt = obj.attribute;
   *ptr = value;
}

int main(){

   CPlusPlusJavaFunctionality obj;

   obj.setValue(10);

   cout<< obj.getValue();  //output: 10

   changeObjectAttribute(obj, 15);

   cout<< obj.getValue();  //output: 15
}

mais ce n'est pas une bonne idée car vous finirez écrire beaucoup de code impliquant avec des pointeurs, qui sont sujettes à des fuites de mémoire et n'oubliez pas d'appeler des destructeurs. Et pour éviter cela c++ ont des constructeurs de copie où vous allez créer une nouvelle mémoire lorsque les objets contenant des pointeurs sont passés à des arguments de fonction qui vont arrêter de manipuler d'autres données d'objets, Java passe par valeur et valeur est Référence, donc il ne nécessite pas de constructeurs de copie.

0
répondu murali krish 2017-01-14 11:55:11

il y a trois méthodes pour passer un objet à une fonction comme paramètre:

  1. Passage par référence
  2. passage par valeur
  3. ajouter constante dans le paramètre

passez par l'exemple suivant:

class Sample
{
public:
    int *ptr;
    int mVar;

    Sample(int i)
    {
        mVar = 4;
        ptr = new int(i);
    }

    ~Sample()
    {
        delete ptr;
    }

    void PrintVal()
    {
        cout << "The value of the pointer is " << *ptr << endl
             << "The value of the variable is " << mVar;
   }
};

void SomeFunc(Sample x)
{
cout << "Say i am in someFunc " << endl;
}


int main()
{

  Sample s1= 10;
  SomeFunc(s1);
  s1.PrintVal();
  char ch;
  cin >> ch;
}

sortie:

Dire que je suis dans someFunc

La valeur du pointeur est -17891602

La valeur de la variable est 4

-1
répondu amerr 2012-10-08 14:24:09

ce qui suit sont les façons de passer des arguments/paramètres pour fonctionner en C++.

1. par valeur.

// passing parameters by value . . .

void foo(int x) 
{
    x = 6;  
}

2. par référence.

// passing parameters by reference . . .

void foo(const int &x) // x is a const reference
{
    x = 6;  
}

// passing parameters by const reference . . .

void foo(const int &x) // x is a const reference
{
    x = 6;  // compile error: a const reference cannot have its value changed!
}

3. par objet.

class abc
{
    display()
    {
        cout<<"Class abc";
    }
}


// pass object by value
void show(abc S)
{
    cout<<S.display();
}

// pass object by reference
void show(abc& S)
{
    cout<<S.display();
}
-1
répondu Yogeesh H T 2015-12-04 06:24:06