Wie übergebe ich Objekte an functionen in C ++?

Ich bin neu in C ++ Programmierung, aber ich habe Erfahrung in Java. Ich brauche Anleitung, wie Objekte an functionen in C ++ übergeben werden.

Muss ich pointers, Referenzen oder Nicht-pointers- und Nicht-Referenzwerte übergeben? Ich erinnere mich, dass es in Java keine solchen Probleme gibt, da wir nur die Variable übergeben, die auf die Objekte verweist.

Es wäre großartig, wenn Sie auch erklären könnten, wo Sie jede dieser Optionen verwenden können.

Solutions Collecting From Web of "Wie übergebe ich Objekte an functionen in C ++?"

Faustregeln für C ++ 11:

Übergabe nach Wert , außer wenn

  1. Sie brauchen keine Eigentumsrechte an dem Objekt und ein einfacher Alias ​​wird es tun. In diesem Fall werden Sie von const reference weitergeleitet .
  2. Sie müssen das Objekt mutieren, in diesem Fall verwenden Sie einen nichtkonstanten L-Wert ,
  3. Sie übergeben Objekte von abgeleiteten classn als Basisklassen. In diesem Fall müssen Sie als Referenz übergeben werden . (Verwenden Sie die vorherigen Regeln, um zu bestimmen, ob const Referenz übergeben wird oder nicht.)

Der pointers wird praktisch nie empfohlen. Optionale Parameter werden am besten als boost::optional ausgedrückt, und das Aliasing wird durch Verweis fein vorgenommen.

Die Bewegungssemantik von C ++ 11 macht die Weitergabe und Rückgabe wertmäßig viel attraktiver, selbst für komplexe Objekte.


Faustregeln für C ++ 03:

Übergeben Sie Argumente mit const Verweis , außer wenn

  1. Sie müssen innerhalb der function geändert werden und solche Änderungen sollten sich nach außen hin spiegeln. In diesem Fall werden Sie von einer nicht const Referenz übergeben
  2. Die function sollte ohne irgendein Argument aufrufbar sein. In diesem Fall übergeben Sie den pointers, so dass Benutzer stattdessen NULL / 0 / nullptr . Wenden Sie die vorherige Regel an, um zu bestimmen, ob Sie einen pointers auf ein const Argument übergeben sollen
  3. sie sind von eingebauten Typen, die durch Kopie weitergegeben werden können
  4. Sie müssen innerhalb der function geändert werden und solche Änderungen sollten nicht nach außen reflektiert werden. In diesem Fall können Sie eine Kopie weitergeben (eine Alternative wäre, gemäß den vorherigen Regeln zu bestehen und eine Kopie innerhalb der function zu erstellen).

(hier wird “pass by value” “pass by copy” genannt, weil die Übergabe nach value immer eine Kopie in C ++ 03 erzeugt)


Es gibt mehr dazu, aber diese wenigen Anfängerregeln werden dich ziemlich weit bringen.

Es gibt einige Unterschiede in den Aufrufkonventionen in C ++ und Java. In C ++ gibt es technisch gesehen nur zwei Konventionen: “Pass-by-Value” und “Pass-by-Reference”, wobei einige Literatur eine dritte Pass-by-Pointer-Konvention enthält (das ist ein pass-by-value eines pointerstyps). Darüber hinaus können Sie dem Typ des Arguments const-ness hinzufügen, um die Semantik zu verbessern.

Durch Verweis gehen

Durch Verweis übergeben bedeutet, dass die function Ihre Objektinstanz und nicht eine Kopie davon konzeptionell empfängt. Die Referenz ist konzeptionell ein Alias ​​für das Objekt, das im aufrufenden Kontext verwendet wurde, und darf nicht null sein. Alle Operationen, die innerhalb der function ausgeführt werden, gelten für das Objekt außerhalb der function. Diese Konvention ist in Java oder C nicht verfügbar.

Übergabe nach Wert (und Pass-by-Pointer)

Der Compiler erzeugt eine Kopie des Objekts im aufrufenden Kontext und verwendet diese Kopie innerhalb der function. Alle Operationen, die innerhalb der function ausgeführt werden, werden für die Kopie ausgeführt, nicht für das externe Element. Dies ist die Konvention für primitive Typen in Java.

Eine spezielle Version davon gibt einen pointers (Adresse des Objekts) in eine function. Die function empfängt den pointers, und alle und alle Operationen, die auf den pointers selbst angewendet werden, werden auf die Kopie (pointers) angewendet, auf der anderen Seite werden Operationen, die auf den dereferenzierten pointers angewendet werden, auf die Objektinstanz an diesem Speicherort angewandt kann Nebenwirkungen haben. Die Auswirkung der Verwendung des Übergabewerts eines pointerss auf das Objekt ermöglicht es der internen function, externe Werte zu ändern, wie bei der Weitergabe nach Referenz, und ermöglicht auch optionale Werte (einen Nullzeiger übergeben).

Dies ist die in C verwendete Konvention, wenn eine function eine externe Variable und die in Java verwendete Konvention mit Referenztypen ändern muss: Die Referenz wird kopiert, aber das referenzierte Objekt ist dasselbe: Änderungen an der Referenz / dem pointers sind außerhalb nicht sichtbar die function, aber Änderungen an dem angegebenen Speicher sind.

Hinzufügen von const zur Gleichung

In C ++ können Sie Objekten Objekte zuweisen, wenn Sie Variablen, pointers und Referenzen auf verschiedenen Ebenen definieren. Sie können eine Variable als konstant deklarieren, Sie können einen Verweis auf eine konstante Instanz deklarieren und Sie können alle pointers auf konstante Objekte, konstante pointers auf veränderbare Objekte und konstante pointers auf konstante Elemente definieren. Umgekehrt kann man in Java nur eine Ebene der constant-ness (final keyword) definieren: das der Variablen (Instanz für primitive Typen, Referenz für Referenztypen), aber man kann keine Referenz auf ein unveränderliches Element definieren (außer die class selbst ist) unveränderlich).

Dies wird häufig in C ++ – Aufrufkonventionen verwendet. Wenn die Objekte klein sind, können Sie das Objekt nach Wert übergeben. Der Compiler wird eine Kopie erstellen, aber diese Kopie ist keine teure Operation. Wenn die function für einen anderen Typ das Objekt nicht ändert, können Sie einen Verweis auf eine konstante Instanz (normalerweise Konstantenreferenz genannt) des Typs übergeben. Dadurch wird das Objekt nicht kopiert, sondern an die function übergeben. Gleichzeitig garantiert der Compiler jedoch, dass das Objekt nicht innerhalb der function verändert wird.

Faustregeln

Dies sind einige grundlegende Regeln zu befolgen:

  • Pass-by-Value für primitive Typen bevorzugen
  • Bevorzugen Sie Pass-by-Reference mit Verweisen auf Konstante für andere Typen
  • Wenn die function das Argument ändern muss, verwenden Sie Pass-by-Reference
  • Wenn das Argument optional ist, verwenden Sie Pass-by-Pointer (auf “constant”, wenn der optionale Wert nicht geändert werden soll).

Es gibt noch andere kleine Abweichungen von diesen Regeln, von denen die erste das Eigentumsrecht an einem Objekt behandelt. Wenn ein Objekt dynamisch mit new zugewiesen wird, muss es mit delete (oder den [] Versionen davon aufgehoben werden). Das Objekt oder die function, die für die Zerstörung des Objekts verantwortlich ist, gilt als Eigentümer der Ressource. Wenn ein dynamisch zugewiesenes Objekt in einem Codeabschnitt erstellt wird, der Besitz jedoch auf ein anderes Element übertragen wird, erfolgt dies normalerweise mit einer Semantik für den Übergabevorgang oder wenn möglich mit intelligenten pointersn.

Randnotiz

Es ist wichtig, auf die Wichtigkeit des Unterschieds zwischen C ++ – und Java-Referenzen zu bestehen. In C ++ sind Verweise konzeptionell die Instanz des Objekts, kein Accessor. Das einfachste Beispiel ist die Implementierung einer Swap-function:

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

Die obige Swap-function ändert beide Argumente durch die Verwendung von Referenzen. Der am nächsten liegende 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 Kopien der Verweise intern ändern, die tatsächlichen Objekte werden jedoch nicht extern geändert. Java-Referenzen sind C-pointers ohne pointersarithmetik, die durch Wert in functionen übergeben werden.

Es gibt mehrere Fälle zu beachten.

Parameter geändert (Parameter “out” und “in / out”)

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

In diesem Fall geht es hauptsächlich um Stil: Soll der Code wie call (obj) oder call (& obj) aussehen ? Es gibt jedoch zwei Punkte, bei denen der Unterschied von Bedeutung ist: der optionale Fall unten, und Sie möchten beim Überladen von Operatoren eine Referenz verwenden.

… 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); 

Das ist der interessante Fall. Die Faustregel lautet “billig zu kopieren” Typen sind nach Wert übergeben – das sind in der Regel kleine Typen (aber nicht immer) – während andere von const ref übergeben werden. Wenn Sie jedoch trotzdem eine Kopie innerhalb Ihrer function erstellen müssen, sollten Sie den Wert übergeben . (Ja, das macht ein bisschen Implementierungsdetails. 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) 

Da ist der geringste Unterschied zwischen allen Situationen, also wähle das, was dein Leben am einfachsten macht.

Const by value ist ein Implementierungsdetail

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

Diese Deklarationen sind eigentlich genau die gleiche function! Bei der Übergabe nach Wert ist const ein Implementierungsdetail. Versuch es:

 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 

Übergabe nach Wert:

 void func (vector v) 

Übergeben Sie Variablen nach Wert, wenn die function vollständige Isolation von der Umgebung benötigt, dh um zu verhindern, dass die function die ursprüngliche Variable ändert, und um zu verhindern, dass andere Threads ihren Wert ändern, während die function ausgeführt wird.

Der Nachteil sind die CPU-Zyklen und der zusätzliche Speicher, der zum Kopieren des Objekts aufgewendet wird.

Pass by const Referenz:

 void func (const vector & v); 

Dieses Formular emuliert Pass-by-Value-Verhalten beim Entfernen des Kopieraufwands. Die function erhält Lesezugriff auf das ursprüngliche Objekt, kann jedoch ihren Wert nicht ändern.

Der Nachteil ist die Thread-Sicherheit: Jede Änderung am ursprünglichen Objekt durch einen anderen Thread wird in der function angezeigt, während sie noch ausgeführt wird.

Überschreiten Sie nicht-const Referenz:

 void func (vector & v) 

Verwenden Sie dies, wenn die function einen Wert in die Variable zurückschreiben muss, der letztendlich vom Aufrufer verwendet wird.

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

Pass by const pointers:

 void func (const vector * vp); 

functionell identisch mit const-reference, mit Ausnahme der unterschiedlichen Syntax, und der Tatsache, dass die aufrufende function einen NULL-pointers übergeben kann, um anzuzeigen, dass keine gültigen Daten übergeben werden.

Nicht threadsicher.

Überschreiten Sie nicht-const pointers:

 void func (vector * vp); 

Ähnlich wie nicht-const Referenz. Der Aufrufer legt die Variable normalerweise auf NULL fest, wenn die function keinen Wert zurückschreiben soll. Diese Konvention wird 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 } } 

Genau wie alle nach Referenz / pointers, nicht Thread sicher.

Da niemand erwähnt, dass ich hinzufügen, Wenn Sie ein Objekt an eine function in C ++ übergeben, wird der Standard-Kopierkonstruktor des Objekts aufgerufen, wenn Sie nicht haben, die einen Klon des Objekts erstellt und dann an die Methode übergeben, so Wenn Sie die Objektwerte ändern, die die Kopie des Objekts anstelle des ursprünglichen Objekts widerspiegeln, ist das das Problem in C ++. Wenn Sie also alle classnattribute als pointers festlegen, kopieren die Kopierkonstruktoren die Adressen des Objekts pointersattribute, also wenn die Methodenaufrufe auf dem Objekt die in pointersattributadressen gespeicherten Werte manipulieren, spiegeln sich die Änderungen auch in dem ursprünglichen Objekt wider, das als ein Parameter übergeben wird, so kann dies dasselbe ein Java sein, aber vergiss nicht, dass all deine class Attribute müssen pointers sein, auch sollten Sie die Werte von pointersn ändern, wird deutlich mit Code Erklärung.

 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 } 

Aber das ist keine gute Idee, da Sie am Ende viel Code mit pointersn schreiben werden, die anfällig für Speicherlecks sind und vergessen Sie nicht Destruktoren zu nennen. Und um dies zu vermeiden, haben copy Konstruktoren, in denen Sie neuen Speicher erstellen, wenn die Objekte, die pointers enthalten, an functionsargumente übergeben werden, die andere Objektdaten manipulieren. Java wird nach Wert übergeben und Wert ist Verweis, so dass keine Kopierkonstruktoren benötigt werden.

Es gibt drei Methoden, ein Objekt als Parameter an eine function zu übergeben:

  1. Durch Verweis gehen
  2. pass auf Wert
  3. Konstante im Parameter hinzufügen

Gehen Sie das folgende Beispiel durch:

 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:

Sag, ich bin in irgendeinem Func
Der Wert des pointerss ist -17891602
Der Wert der Variablen ist 4

Im Folgenden finden Sie die Möglichkeiten, Argumente / Parameter an C ++ zu übergeben.

1. nach Wert.

 // passing parameters by value . . . void foo(int x) { x = 6; } 

2. durch Bezugnahme.

 // 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. nach Objekt.

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