Frage

Ich bin neu in C++ - Programmierung, aber ich habe Erfahrung in Java.Ich brauche eine Anleitung zum übergeben von Objekten an Funktionen in C++.

Muss ich übergeben von Zeigern, Referenzen, oder nicht-Zeiger-und nicht-Referenz-Werte?Ich erinnere mich, in Java gibt es keine derartigen Probleme, da wir übergeben nur die Variablen, die hält Verweis auf die Objekte.

Es wäre toll, wenn könnten Sie auch erklären, wo die Verwendung der einzelnen Optionen.

War es hilfreich?

Lösung

Faustregeln für die C++11:

Pass von Wert, werden , außer beim

  1. Sie brauchen nicht das Eigentum des Objekts und einen einfachen alias tun, in welchem Fall Sie pass durch const Referenz,
  2. Sie müssen mutieren Sie das Objekt, in dem Fall verwenden Sie pass durch eine nicht-const lvalue-Referenz,
  3. übergeben Sie Objekte von abgeleiteten Klassen als Basisklassen in diesem Fall müssen Sie pass by reference.(Verwenden Sie die vorherigen Regeln, um zu bestimmen, ob zu pass durch const Referenz-oder nicht.)

Vorbei Zeiger ist praktisch nie hingewiesen.Optionale Parameter werden am besten ausgedrückt std::optional (boost::optional für ältere std-libs), und aliasing ist fein gemacht durch Referenz.

C++11 move-Semantik stellen die übergabe und Rückgabe von Wert deutlich attraktiver, auch für komplexe Objekte.


Faustregeln für die C++03:

Argumente von const Referenz, werden , außer beim

  1. Sie wurde innerhalb der Funktion, und solche änderungen werden sollte, spiegelt sich außerhalb, in welchem Fall Sie pass durch nicht-const Referenz
  2. die Funktion sollte aufrufbar sein, ohne argument, in diesem Fall übergeben Sie durch Zeiger, so dass die Benutzer können passieren NULL/0/nullptr statt;anwenden der vorherigen Regel, um zu bestimmen, ob Sie sollten durch einen Zeiger übergeben, um eine const argument
  3. Sie sind der built-in-Typen, die bestanden kopieren
  4. Sie wurde innerhalb der Funktion und solche änderungen sollten nicht reflektiert werden außerhalb, dann können Sie pass Kopie (eine alternative wäre zu übergeben, die nach den bisherigen Vorschriften und eine Kopie innerhalb der Funktion)

(hier "pass by value" genannt wird "pass " kopieren", weil als Wert übergeben werden, erzeugt immer eine Kopie in C++03)


Es gibt mehr dazu, aber diese paar Anfänger die Regeln kommen Sie ziemlich weit.

Andere Tipps

Es gibt einige Unterschiede in der Aufruf-Konventionen in C++ und Java.In C++ gibt es technisch gesehen nur zwei Konventionen:pass-by-value und pass-by-reference mit einigen Literatur einschließlich der Dritte pass-by-pointer-Konvention (das ist eigentlich pass-by-Wert ein Zeiger-Typ).Auf top von, dass, Sie können hinzufügen const-ness, um den Typ des Arguments, die Verbesserung der Semantik.

Pass by reference

Übergabe per Referenz heißt, dass die Funktion wird konzeptionell erhalten Ihre Objekt-Instanz und nicht eine Kopie davon.Die Referenz ist konzeptionell ein alias für das Objekt, das verwendet wurde, in den aufrufenden Kontext und kann nicht null sein.Alle Operationen, die in der Funktion für das Objekt, außerhalb der Funktion.Dieses übereinkommen ist nicht in Java oder C.

Als Wert übergeben (und die pass-by-pointer)

Der compiler generiert eine Kopie des Objekts in den aufrufenden Kontext und benutzen Sie die Kopie innerhalb der Funktion.Alle Operationen, die in der Funktion sind durchgeführt auf die Kopie, nicht das externe element.Dies ist die Konvention für primitive Typen in Java.

Eine spezielle version von es ist vorbei ein Zeiger (Adresse-der-Objekt) in eine Funktion.Die Funktion erhält den Zeiger, und alle Operationen angewendet, um den Zeiger selbst angewendet werden, um die Kopie (Zeiger), auf der anderen Seite, Operationen angewendet, um den Zeiger dereferenziert wird, gelten für die Objekt-Instanz an, dass der Speicher Position, so dass die Funktion, die Nebenwirkungen haben können.Die Wirkung der Verwendung von pass-by-Wert ein Zeiger auf das Objekt ermöglichen die interne Funktion zum ändern äußere Werte, als mit pass-by-Referenz und ermöglichen auch optionale Werte (übergeben Sie einen null-Zeiger).

Dies ist die Konvention in C verwendet, wenn eine Funktion ändern muss eine externe variable, und die Konvention in Java mit Referenz-Typen:die Referenz kopiert wird, sondern das genannte Objekt ist das gleiche:änderungen, um den Verweis/Zeiger werden nicht außerhalb der Funktion sichtbar, aber änderungen an den Spitzen Speicher sind.

Hinzufügen const die Gleichung

In C++ können Sie ordnen konstant-ness, um Objekte bei der Definition von Variablen, Zeiger und Referenzen auf verschiedenen Ebenen.Sie können eine variable deklarieren, werden konstant ist, kann man deklarieren Sie eine Referenz auf eine Konstante Instanz, und Sie können festlegen, alle Zeiger auf Konstante Objekte, Konstanten Zeiger auf veränderbare Objekte und Konstante Zeiger auf Konstante Elemente.Umgekehrt in Java können Sie nur definieren, eine Ebene von Konstanten-ness (Schlüsselwort final):dass die variable (Instanz für primitive Typen, Bezug für Referenz-Typen), aber man kann nicht definieren, eine Referenz auf ein unveränderliches element (es sei denn, der Klasse selbst ist unveränderlich).

Dies ist weitgehend verwendet in C++ aufrufen von Konventionen.Wenn die Objekte, die klein sind, die Sie übergeben können das Objekt durch einen Wert.Der compiler generiert eine Kopie, aber das kopieren ist nicht eine teure operation ist.Für jede andere Art, wenn die Funktion nicht ändern, das Objekt, übergeben Sie eine Referenz auf eine Konstante Instanz (gewöhnlich als Konstante Referenz) des Art.Dies wird keine Kopie des Objekts, sondern übergeben Sie es in die Funktion.Aber zur gleichen Zeit wird der compiler garantieren, dass das Objekt nicht geändert wird innerhalb der Funktion.

Faustregeln

Dies sind einige grundlegende Regeln zu befolgen:

  • Lieber, pass-by-Wert für primitive Typen
  • Lieber, pass-by-reference mit Referenzen auf Konstante für andere Arten
  • Wenn die Funktion zum ändern der argument-verwenden Sie die pass-by-reference
  • Wenn das argument optional ist, verwenden Sie die pass-by-pointer, um dann konstant, wenn der optionale Wert sollte nicht geändert werden)

Es gibt andere kleine Abweichungen von diesen Regeln, von denen die erste ist der Umgang mit Eigentum an einem Objekt.Wenn Sie ein Objekt dynamisch mit new zugewiesen wurden, muss es freigegeben ist, mit löschen (oder die [] - Versionen davon).Das Objekt oder die Funktion, die verantwortlich ist für die Zerstörung des Objekts ist, als der Eigentümer der Ressource.Bei einer dynamisch zugewiesenen Objekt erstellt wird, in der ein Stück code, aber der Besitz wird übertragen auf ein anderes element, es ist in der Regel getan mit pass-by-pointer-Semantik, oder, wenn möglich, mit smart-Pointer.

Anmerkung

Es ist wichtig, darauf zu bestehen, in der die Bedeutung der Unterschied zwischen C++ - und Java-Referenzen.In C++ - Referenzen sind im Prinzip die Instanz des Objekts, nicht einen accessor zu.Das einfachste Beispiel ist die Umsetzung eines swap-Funktion:

// 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 ); 
}

Der swap-Funktion oben änderungen sowohl seine Argumente durch die Verwendung von Referenzen.Die nächsten code in 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
   }
}

Die Java-version des Codes wird die Kopie ändern der Verweise, die intern, aber ändern nicht die tatsächlichen Objekte von außen.Java-Referenzen sind in C-Zeiger, ohne Zeiger-Arithmetik, die erhalten Wert übergeben an Funktionen.

Es gibt mehrere Fälle zu berücksichtigen.

Parameter geändert ( "out" und "in / out" Parameter)

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

Dieser Fall ist vor allem über Stil: wollen Sie den Code aussehen call (obj) oder call (& obj) ? Allerdings gibt es zwei Punkte, wo die Differenz Angelegenheiten. Die optionale Fall unten, und Sie möchten einen Verweis verwenden, wenn Betreiber Überlastung

... und optional

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

Parameter nicht geändert

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

Dies ist der Fall interessant. Die Faustregel „billig kopieren“ Typen von Wert übergeben werden - diese sind in der Regel kleine Arten (aber nicht immer) - während andere von const ref übergeben werden. Wenn Sie jedoch müssen unabhängig eine Kopie in Ihrer Funktion zu machen, Sie sollte Wert passieren. (Ja, Dies legt ein wenig Implementierungsdetail. C'est le C ++. )

... und optional

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

Es ist der mindeste Unterschied zwischen allen Situationen, so zu wählen, je nachdem, was macht Ihr Leben am einfachsten.

Const von Wert ist eine Implementierung Detail

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

Diese Erklärungen tatsächlich die genau die gleiche Funktion! Wenn nach Wert vorbei, const ist rein eine Implementierung Detail. es ausprobieren:

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

Pass von Wert:

void func (vector v)

Pass Variablen von Wert, wenn die Funktion benötigt vollständige Isolation von der Umgebung das heißt, die Funktion zu verhindern, dass von der Original-variable Modifizieren sowie zu anderen Threads zu verhindern, dessen Wert modifizierende während die Funktion ausgeführt wird.

Der Nachteil ist die CPU-Zyklen und zusätzliche Speicher ausgegeben, das Objekt zu kopieren.

Pass durch konstante Referenz:

void func (const vector& v);

Diese Form emuliert Pass-by-Wert Verhalten während des Kopierens über Kopf entfernt wird. Die Funktion erhält Lesezugriff auf das ursprüngliche Objekt, kann aber seinen Wert nicht ändern.

Der Nachteil ist, Thread-Sicherheit:. Jede Änderung auf das ursprüngliche Objekt von einem anderen Thread gemacht wird innerhalb der Funktion zeigt schon während der Ausführung

Pass durch nicht konstante Referenz:

void func (vector& v)

Verwenden, wenn die Funktion hat einen gewissen Wert auf die Variable schreiben zurück, die letztlich vom Anrufer gewöhnen wird.

Genau wie der const Referenzfall ist dies nicht Thread-sicher.

Pass von const Zeiger:

void func (const vector* vp);

Funktional gleiche wie Pass von const-Referenz mit Ausnahme der anderen Syntax, wie die Tatsache, dass die anrufende Funktion NULL-Zeiger übergeben kann, um anzuzeigen es keine gültigen Daten hat zu bestehen.

nicht Thread-sicher.

Pass von nicht-const Zeiger:

void func (vector* vp);

Ähnlich nicht konstante Referenz. Der Anrufer legt normalerweise die Variable auf NULL, wenn die Funktion keinen Wert zurückschreiben soll. Diese Konvention ist in vielen glibc APIs gesehen. Beispiel:

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

Wie alle Pass von Verweis / Zeiger, nicht Thread-sicher.

Da niemand erwähnte ich es bin Hinzufügen Wenn Sie ein Objekt an eine Funktion in c geben ++ Standard Copykonstruktor des Objekts aufgerufen wird, wenn Sie eine nicht haben, die einen Klon des Objekts erstellt und dann an den Pass Verfahren, so dass, wenn Sie die Objektwerte ändern, die auf der Kopie des Objekts anstelle des ursprünglichen Objekts reflektiert wird, das ist das Problem in c ++, wenn Sie also die Klasse machen alle Attribute Zeiger sein, dann kopiert die Kopierkonstruktoren die so Adressen der Zeiger Attribute, wenn die Methodenaufrufe auf dem Objekt, das die Werte in Zeigerattribute Adressen gespeichert manipuliert, spiegeln die Änderungen auch in das ursprüngliche Objekt, das als Parameter übergeben wird, so dass diese gleichen ein Java verhalten können, aber vergessen Sie nicht, dass alle Klassenattribute müssen Zeiger sein, auch sollten Sie die Werte der Zeiger ändern, wird mit dem Code Erklärung viel klar sein.

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
}

Das ist aber nicht gute Idee, wie Sie vielen Code mit Zeigern die das Schreiben enden werden, die Speicherlecks anfällig sind und nicht vergessen Destruktoren zu nennen. Und diese c zu vermeiden ++ Kopierkonstruktoren, wo Sie neue Speicher schaffen werden, wenn die Objekte enthalten Zeiger auf Funktion Argumente übergeben werden, die anderen Objekte Daten manipulieren stoppen, tut Java Pass von Wert und Wert Bezug, so ist es nicht erfordern Konstrukteurs kopieren.

Es gibt drei Methoden ein Objekt auf eine Funktion als Parameter übergeben:

  1. Pass durch Verweis
  2. Pass von Wert
  3. Hinzufügen Konstante im Parameter

Gehen Sie das folgende Beispiel:

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

Ausgabe:

  

sagen, ich bin in someFunc
  Der Wert des Zeigers ist -17891602
  Der Wert der Variablen 4

Im Folgenden werden die Möglichkeiten, um ein Argument / Parameter-Funktion in C ++ passieren.

1. von Wert.

// passing parameters by value . . .

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

2. Bezug genommen wird.

// 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. durch das Objekt.

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();
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top