Warum werden Objekte als Referenz übergeben?

31

Ein junger Mitarbeiter, der OO studierte, hat mich gefragt, warum jedes Objekt als Referenz übergeben wird, was das Gegenteil von primitiven Typen oder Strukturen ist. Es ist ein gemeinsames Merkmal von Sprachen wie Java und C #.

Ich konnte keine gute Antwort für ihn finden.

Was sind die Beweggründe für diese Designentscheidung? Hatten die Entwickler dieser Sprachen es satt, jedes Mal Zeiger und Typedefs erstellen zu müssen?

Gustavo Cardoso
quelle
2
Fragen Sie sich, warum Sie in Java und C # Parameter als Verweis statt als Wert oder als Verweis statt als Zeiger übergeben haben?
Robert
@Robert, gibt es auf der hohen Ebene einen Unterschied zwischen "Referenz statt per Zeiger"? Glaubst du, ich sollte den Titel in "Warum sind Objekte immer Referenzen?" Ändern?
Gustavo Cardoso
Referenzen sind Hinweise.
Compman
2
@Anto: Eine Java-Referenz ist in jeder Hinsicht identisch mit einem ordnungsgemäß verwendeten C-Zeiger (ordnungsgemäß verwendet: keine Typumwandlung, kein ungültiger Speicher, kein Literal).
Zan Lynx
5
Um auch wirklich pedantisch zu sein, ist der Titel falsch (zumindest was .net betrifft). Objekte werden NICHT als Referenz übergeben, Referenzen werden als Wert übergeben. Wenn Sie ein Objekt an eine Methode übergeben, wird der Referenzwert in eine neue Referenz innerhalb des Methodenkörpers kopiert. Ich finde es schade, dass "Objekte als Referenz übergeben werden" in die Liste der gängigen Programmierer-Anführungszeichen aufgenommen wurde, wenn sie falsch sind und zu einem schlechteren Verständnis von Referenzen für neue Programmierer führen.
SecretDeveloper

Antworten:

15

Die Hauptgründe dafür sind:

  • Zeiger sind technisch richtig zu machen
  • Sie benötigen Zeiger, um bestimmte Datenstrukturen zu implementieren
  • Sie benötigen Zeiger, um die Speichernutzung effizient zu gestalten
  • Sie benötigen keine manuelle Speicherindizierung, wenn Sie die Hardware nicht direkt verwenden.

Daher Referenzen.

Paul Nathan
quelle
32

Einfache Antwort:

Minimierung des Speicherverbrauchs
und der
CPU-Zeit bei der Neuerstellung und Erstellung einer vollständigen Kopie jedes Objekts, das irgendwo übergeben wurde.

Tim
quelle
Ich stimme Ihnen zu, aber ich denke, dass es auch eine ästhetische oder OO-Design-Motivation gibt.
Gustavo Cardoso
9
@Gustavo Cardoso: "etwas ästhetische oder OO-Design-Motivation". Nein, es ist einfach eine Optimierung.
S.Lott
6
@ S.Lott: Nein, es ist in OO-Begriffen sinnvoll, als Referenz zu übergeben, da Sie semantisch keine Kopien von Objekten erstellen möchten. Sie möchten das Objekt übergeben, anstatt eine Kopie davon zu erstellen. Wenn Sie als Wert übergeben, wird die OO-Metapher etwas verletzt, da all diese Klone von Objekten überall erzeugt werden, die auf einer höheren Ebene keinen Sinn ergeben.
Intuited
@Gustavo: Ich denke, wir streiten den gleichen Punkt. Sie erwähnen die Semantik von OOP und verweisen darauf, dass die Metapher von OOP zusätzliche Gründe für meine eigene sind. Es scheint mir, dass die Macher des OOP es so gemacht haben, wie sie es getan haben, um "den Speicherverbrauch zu minimieren" und "CPU-Zeit zu sparen"
Tim
14

In C ++ haben Sie zwei Hauptoptionen: Rückgabe nach Wert oder Rückgabe nach Zeiger. Schauen wir uns den ersten an:

MyClass getNewObject() {
    MyClass newObj;
    return newObj;
}

Angenommen, Ihr Compiler ist nicht schlau genug, um die Rückgabewertoptimierung zu verwenden, dann geschieht Folgendes:

  • newObj wird als temporäres Objekt erstellt und auf dem lokalen Stapel abgelegt.
  • Eine Kopie von newObj wird erstellt und zurückgegeben.

Wir haben das Objekt sinnlos kopiert. Dies ist eine Verschwendung von Verarbeitungszeit.

Schauen wir uns stattdessen return-by-pointer an:

MyClass* getNewObject() {
    MyClass newObj = new MyClass();
    return newObj;
}

Wir haben die überflüssige Kopie entfernt, aber jetzt haben wir ein weiteres Problem eingeführt: Wir haben ein Objekt auf dem Heap erstellt, das nicht automatisch zerstört wird. Wir müssen uns selbst darum kümmern:

MyClass someObj = getNewObject();
delete someObj;

Zu wissen, wer für das Löschen eines auf diese Weise zugewiesenen Objekts verantwortlich ist, kann nur durch Kommentare oder Konventionen mitgeteilt werden. Es kommt leicht zu Speicherlecks.

Es wurden viele Umgehungsmöglichkeiten vorgeschlagen, um diese beiden Probleme zu lösen - die Rückgabewertoptimierung (bei der der Compiler klug genug ist, die redundante Kopie nicht als Rückgabe nach Wert zu erstellen), indem ein Verweis auf die Methode übergeben wird (die Funktion injiziert also in eine vorhandenes Objekt, anstatt ein neues zu erstellen), intelligente Zeiger (so dass die Frage des Eigentums strittig ist).

Die Java / C # -Ersteller erkannten, dass es eine bessere Lösung ist, Objekte immer als Referenz zurückzugeben, insbesondere, wenn die Sprache dies von Haus aus unterstützt. Es knüpft an viele andere Funktionen der Sprachen an, wie z. B. die Speicherbereinigung usw.

Ameise
quelle
Return-by-Value ist schon schlimm genug, aber Pass-by-Value ist noch schlimmer, wenn es um Objekte geht, und ich denke, das war das eigentliche Problem, das sie zu vermeiden versuchten.
Mason Wheeler
Sie haben sicher einen gültigen Punkt. Das OO-Designproblem, auf das @Mason hinwies, war jedoch die letzte Motivation für die Änderung. Es hatte keine Bedeutung, den Unterschied zwischen Referenz und Wert beizubehalten, wenn Sie nur die Referenz verwenden möchten.
Gustavo Cardoso
10

Viele andere Antworten haben gute Infos. Ich möchte einen wichtigen Punkt zum Klonen hinzufügen , der nur teilweise angesprochen wurde.

Referenzen zu verwenden ist klug. Das Kopieren von Dingen ist gefährlich.

Wie andere gesagt haben, gibt es in Java keinen natürlichen "Klon". Dies ist nicht nur eine fehlende Funktion. Sie möchten niemals einfach jede Eigenschaft in einem Objekt kopieren (egal ob flach oder tief). Was wäre, wenn diese Eigenschaft eine Datenbankverbindung wäre? Sie können eine Datenbankverbindung nicht mehr "klonen", als Sie einen Menschen klonen können. Die Initialisierung ist aus einem bestimmten Grund vorhanden.

Tiefe Kopien sind ein eigenes Problem - wie tief gehen Sie wirklich ? Sie konnten definitiv nichts kopieren, was statisch ist (einschließlich aller ClassObjekte).

Aus dem gleichen Grund, warum es keinen natürlichen Klon gibt, würden Objekte, die als Kopien übergeben werden , Wahnsinn erzeugen . Auch wenn Sie eine DB-Verbindung "klonen" könnten - wie würden Sie jetzt sicherstellen, dass sie geschlossen ist?


* Siehe die Kommentare - Mit dieser "never" -Anweisung meine ich einen automatischen Klon , der jede Eigenschaft klont. Java hat keine bereitgestellt, und aus den hier aufgeführten Gründen ist es für Sie als Benutzer der Sprache wahrscheinlich keine gute Idee, eine eigene zu erstellen. Das Klonen nur von nicht transienten Feldern wäre ein Anfang, aber selbst dann müssten Sie sorgfältig definieren, transientwo dies angebracht ist.

Nicole
quelle
Ich habe Probleme, den Sprung von guten Einwänden zum Klonen unter bestimmten Bedingungen zu der Aussage zu verstehen, dass es nie gebraucht wird. Und ich habe Situationen erlebt, in denen ein genaues Duplikat benötigt wurde, in denen keine statischen Funktionen beteiligt waren, keine E / A-Vorgänge oder offenen Verbindungen in Frage kamen ... Ich verstehe die Risiken des Klonens, kann die Decke jedoch nie sehen .
Inca
2
@Inca - Du verstehst mich vielleicht falsch. Absichtlich umgesetzt cloneist in Ordnung. Mit "wohl oder übel" meine ich das Kopieren aller Eigenschaften, ohne darüber nachzudenken - ohne absichtliche Absicht. Die Java-Sprachdesigner erzwangen diese Absicht, indem sie eine vom Benutzer erstellte Implementierung von forderten clone.
Nicole
Verweise auf unveränderliche Objekte zu verwenden ist klug. Einfache Werte wie Datum veränderbar zu machen und dann mehrere Verweise darauf zu erstellen, ist nicht so.
Kevin Cline
@NickC: Der Hauptgrund dafür, dass "Dinge wohl oder übel klonen" gefährlich ist, besteht darin, dass Sprachen / Frameworks wie Java und .net keine Möglichkeit haben, deklarativ anzugeben, ob eine Referenz den veränderlichen Zustand, die Identität, beides oder keines von beiden einschließt. Wenn das Feld eine Objektreferenz enthält, die einen veränderlichen Status, aber keine Identität enthält, muss beim Klonen des Objekts das Objekt, das den Status enthält, dupliziert und eine Referenz auf dieses Duplikat im Feld gespeichert werden. Wenn die Referenz Identität, aber keinen veränderlichen Status enthält, muss sich das Feld in der Kopie auf dasselbe Objekt wie im Original beziehen.
Supercat
Der Deep-Copy-Aspekt ist ein wichtiger Punkt. Das Kopieren von Objekten ist problematisch, wenn sie Verweise auf andere Objekte enthalten, insbesondere wenn der Objektgraph veränderbare Objekte enthält.
Caleb
4

Objekte werden in Java immer referenziert. Sie werden nie um sich herum weitergegeben.

Ein Vorteil ist, dass dies die Sprache vereinfacht. Ein C ++ - Objekt kann als Wert oder als Referenz dargestellt werden, sodass für den Zugriff auf ein Mitglied zwei verschiedene Operatoren verwendet werden müssen: .und ->. (Es gibt Gründe, warum dies nicht konsolidiert werden kann. Beispielsweise sind intelligente Zeiger Werte, die Referenzen sind und diese voneinander unterscheiden müssen.) Java benötigt nur ..

Ein weiterer Grund ist, dass der Polymorphismus nicht nach Wert, sondern nach Referenz erfolgen muss. Ein durch value behandeltes Objekt ist nur dort und hat einen festen Typ. Es ist möglich, dies in C ++ zu vermasseln.

Außerdem kann Java die Standardzuweisung / Kopie / was auch immer ändern. In C ++ ist es eine mehr oder weniger tiefe Kopie, während es in Java eine einfache Zeigerzuweisung / copy / whatever ist, mit .clone()und für den Fall, dass Sie kopieren müssen.

David Thornley
quelle
Manchmal wird es wirklich hässlich, wenn Sie '(* object) ->'
Gustavo Cardoso
1
Es ist erwähnenswert, dass C ++ zwischen Zeigern, Referenzen und Werten unterscheidet. SomeClass * ist ein Zeiger auf ein Objekt. SomeClass & ist eine Referenz auf ein Objekt. SomeClass ist ein Werttyp.
Ant
Ich habe @Rober bereits bei der ersten Frage gefragt, aber ich werde es auch hier tun: Der Unterschied zwischen * und & in C ++ ist nur eine technische Kleinigkeit, nicht wahr? Sind sie auf hoher Ebene semantisch gleich?
Gustavo Cardoso
3
@ Gustavo Cardoso: Der Unterschied ist semantisch; auf einem niedrigen technischen Niveau sind sie im Allgemeinen identisch. Ein Zeiger zeigt auf ein Objekt oder ist NULL (ein definierter ungültiger Wert). Es sei denn const, sein Wert kann geändert werden, um auf andere Objekte zu verweisen. Eine Referenz ist ein anderer Name für ein Objekt, kann nicht NULL sein und kann nicht neu platziert werden. Es wird im Allgemeinen durch einfache Verwendung von Zeigern implementiert, aber das ist ein Implementierungsdetail.
David Thornley
+1 für "Polymorphismus muss durch Bezugnahme erfolgen." Das ist ein unglaublich wichtiges Detail, das die meisten anderen Antworten ignoriert haben.
Doval
4

Ihre ursprüngliche Aussage zu C # -Objekten, die als Referenz übergeben werden, ist nicht korrekt. In C # sind Objekte Referenztypen, aber standardmäßig werden sie wie Werttypen als Wert übergeben. Im Fall eines Referenztyps ist der "Wert", der als Methodenparameter für die Übergabe von Werten kopiert wird, die Referenz selbst, sodass Änderungen an den Eigenschaften innerhalb einer Methode außerhalb des Methodenbereichs wirksam werden.

Wenn Sie jedoch die Parametervariable selbst innerhalb einer Methode neu zuweisen, werden Sie feststellen, dass diese Änderung nicht außerhalb des Methodenbereichs wirksam wird. Wenn Sie dagegen einen Parameter mithilfe des refSchlüsselworts als Referenz übergeben , funktioniert dieses Verhalten wie erwartet.

Newdayrising
quelle
3

Schnelle Antwort

Die Designer von Java und anderen Sprachen wollten das Konzept "Alles ist ein Objekt" anwenden. Das Übergeben von Daten als Referenz ist sehr schnell und beansprucht nicht viel Speicher.

Zusätzlicher erweiterter langweiliger Kommentar

Obwohl diese Sprachen Objektreferenzen verwenden (Java, Delphi, C #, VB.NET, Vala, Scala, PHP), ist die Wahrheit, dass Objektreferenzen Zeiger auf Objekte in Verkleidung sind. Der Nullwert, die Speicherzuordnung, die Kopie einer Referenz, ohne die gesamten Daten eines Objekts zu kopieren, allesamt Objektzeiger, keine reinen Objekte !!!

In Object Pascal (nicht Delphi), anc C ++ (nicht Java, nicht C #) kann ein Objekt als statisch zugewiesene Variable deklariert werden, und auch mit einer dynamisch zugewiesenen Variablen, indem ein Zeiger ("Objektreferenz" ohne " Zuckersyntax "). Jeder Fall verwendet eine bestimmte Syntax, und es gibt keine Möglichkeit, wie in Java "und Freunde" zu verwechseln. In diesen Sprachen kann ein Objekt sowohl als Wert als auch als Referenz übergeben werden.

Der Programmierer weiß, wann eine Zeigersyntax erforderlich ist und wann nicht, aber in Java und ähnlichen Sprachen ist dies verwirrend.

Bevor Java existierte oder Mainstream wurde, lernten viele Programmierer OO in C ++ ohne Zeiger, wobei sie bei Bedarf nach Wert oder Referenz übergaben. Beim Wechsel von Lern- zu Geschäftsanwendungen werden normalerweise Objektzeiger verwendet. Die QT-Bibliothek ist dafür ein gutes Beispiel.

Als ich Java lernte, versuchte ich, dem Konzept eines Objekts zu folgen, war aber beim Codieren verwirrt. Schließlich sagte ich "ok, dies sind Objekte, die dynamisch mit einem Zeiger mit der Syntax eines statisch zugewiesenen Objekts zugewiesen wurden" und hatte erneut keine Probleme beim Codieren.

umlcat
quelle
3

Java und C # übernehmen die Kontrolle über den Low-Level-Speicher von Ihnen. Der "Haufen", auf dem sich die von Ihnen erstellten Objekte befinden, lebt sein eigenes Leben. Beispielsweise kann der Garbage Collector Objekte nach Belieben abrufen.

Da es eine separate Indirektionsebene zwischen Ihrem Programm und diesem "Heap" gibt, sind die beiden Möglichkeiten, auf ein Objekt nach Wert und Zeiger (wie in C ++) zu verweisen, nicht mehr zu unterscheiden verweisen : Sie verweisen immer auf Objekte, auf die "per Zeiger" verwiesen wird irgendwo auf dem Haufen. Aus diesem Grund wird Pass-by-Reference bei einem solchen Entwurfsansatz zur Standardsemantik der Zuweisung. Java, C #, Ruby und so weiter.

Das Obige betrifft nur imperative Sprachen. In den oben erwähnten Sprachen wird die Kontrolle über den Speicher an die Laufzeit übergeben, aber das Sprachdesign sagt auch "Hey, aber tatsächlich gibt es den Speicher und es gibt die Objekte und sie tun das Gedächtnis besetzen“. Funktionale Sprachen werden noch abstrakter, indem der Begriff "Erinnerung" von ihrer Definition ausgeschlossen wird. Aus diesem Grund gilt die Referenzübergabe nicht unbedingt für alle Sprachen, in denen Sie den Low-Level-Speicher nicht steuern können.

P Shved
quelle
2

Ich kann mir ein paar Gründe vorstellen:

  • Das Kopieren primitiver Typen ist trivial und wird normalerweise in eine Maschinenanweisung übersetzt.

  • Das Kopieren von Objekten ist nicht trivial. Das Objekt kann Elemente enthalten, die selbst Objekte sind. Das Kopieren von Objekten kostet CPU-Zeit und Speicher. Abhängig vom Kontext gibt es sogar mehrere Möglichkeiten, ein Objekt zu kopieren.

  • Das Übergeben von Objekten als Referenz ist kostengünstig und wird auch dann nützlich, wenn Sie die Objektinformationen zwischen mehreren Clients des Objekts teilen / aktualisieren möchten.

  • Komplexe Datenstrukturen (insbesondere solche, die rekursiv sind) erfordern Zeiger. Das Übergeben von Objekten als Referenz ist nur eine sicherere Methode zum Übergeben von Zeigern.

Jeroko
quelle
1

Andernfalls sollte die Funktion in der Lage sein, automatisch eine (offensichtlich tiefe) Kopie aller Arten von Objekten zu erstellen, die an sie übergeben werden. Und normalerweise kann es nicht erraten, um es zu machen. Sie müssten also die Implementierung der Kopier- / Klon-Methode für alle Ihre Objekte / Klassen definieren.

David
quelle
Könnte es einfach eine flache Kopie machen und die tatsächlichen Werte und Zeiger auf andere Objekte behalten?
Gustavo Cardoso
#Gustavo Cardoso, dann könnten Sie andere Objekte über dieses ändern. Würden Sie das von einem Objekt erwarten, das NICHT als Referenz übergeben wurde?
David
0

Weil Java als besseres C ++ und C # als besseres Java entworfen wurde und die Entwickler dieser Sprachen das grundlegend kaputte C ++ - Objektmodell satt hatten, bei dem Objekte Werttypen sind.

Zwei der drei Grundprinzipien der objektorientierten Programmierung sind Vererbung und Polymorphismus, und die Behandlung von Objekten als Werttypen anstelle von Referenztypen ist mit beiden verheerend. Wenn Sie ein Objekt als Parameter an eine Funktion übergeben, muss der Compiler wissen, wie viele Bytes übergeben werden sollen. Wenn es sich bei Ihrem Objekt um einen Referenztyp handelt, ist die Antwort einfach: Die Größe eines Zeigers, die für alle Objekte gleich ist. Wenn es sich bei Ihrem Objekt jedoch um einen Werttyp handelt, muss er die tatsächliche Größe des Werts übergeben. Da eine abgeleitete Klasse neue Felder hinzufügen kann, bedeutet dies sizeof (abgeleitet)! = Sizeof (Basis), und der Polymorphismus verschwindet aus dem Fenster.

Hier ist ein einfaches C ++ - Programm, das das Problem demonstriert:

#include <iostream> 
class Parent 
{ 
public: 
   int a;
   int b;
   int c;
   Parent(int ia, int ib, int ic) { 
      a = ia; b = ib; c = ic;
   };
   virtual void doSomething(void) { 
      std::cout << "Parent doSomething" << std::endl;
   }
};

class Child : public Parent {
public:
   int d;
   int e;
   Child(int id, int ie) : Parent(1,2,3) { 
      d = id; e = ie;
   };
   virtual void doSomething(void) {
      std::cout << "Child doSomething : D = " << d << std::endl;
   }
};

void foo(Parent a) {
   a.doSomething();
}

int main(void)
{
   Child c(4, 5);
   foo(c);
   return 0;
}

Die Ausgabe dieses Programms entspricht nicht der eines entsprechenden Programms in einer vernünftigen OO-Sprache, da Sie ein abgeleitetes Objekt nicht als Wert an eine Funktion übergeben können, die ein Basisobjekt erwartet. Der Compiler erstellt daher einen Konstruktor für verborgene Kopien und übergibt diesen eine Kopie des übergeordneten Teils des untergeordneten Objekts , anstatt das untergeordnete Objekt wie von Ihnen angegeben zu übergeben. Versteckte semantische Fallstricke wie dieser sind der Grund, warum das Übergeben von Objekten als Wert in C ++ vermieden werden sollte und in fast jeder anderen OO-Sprache überhaupt nicht möglich ist.

Mason Wheeler
quelle
Sehr guter Punkt. Ich habe mich jedoch auf Rückkehrprobleme konzentriert, da es einige Mühe kostet, diese zu umgehen. Dieses Programm kann durch Hinzufügen eines einfachen kaufmännischen Und behoben werden: void foo (Parent & a)
Ant
OO funktioniert wirklich nicht richtig ohne Zeiger
Gustavo Cardoso
-1.000000000000
P Shved
5
Es ist wichtig , daran zu erinnern , Java ist Pass-by-Wert (es geht Objektreferenzen nach Wert, während Primitiven rein von Wert übergeben werden).
Nicole
3
@Pavel Shved - "Zwei sind besser als einer!" Oder mit anderen Worten, mehr Seil zum Aufhängen.
Nicole
0

Denn sonst gäbe es keinen Polymorphismus.

In der OO-Programmierung können Sie eine größere DerivedKlasse aus einer erstellen Baseund sie dann an Funktionen übergeben, die a erwartenBase Eins . Ziemlich trivial, oder?

Mit der Ausnahme, dass die Größe des Arguments einer Funktion feststeht und zur Kompilierungszeit festgelegt wird. Sie können alles darüber streiten, was Sie wollen, ausführbarer Code ist wie folgt, und Sprachen müssen an der einen oder anderen Stelle ausgeführt werden (rein interpretierte Sprachen sind hierdurch nicht eingeschränkt ...)

Nun gibt es ein Datenelement, das auf einem Computer genau definiert ist: die Adresse einer Speicherzelle, die normalerweise als ein oder zwei "Wörter" ausgedrückt wird. Es ist entweder als Zeiger oder Referenzen in Programmiersprachen sichtbar.

Um also Objekte beliebiger Länge zu übergeben, ist es am einfachsten, einen Zeiger / Verweis auf dieses Objekt zu übergeben.

Dies ist eine technische Einschränkung der OO-Programmierung.

Aber da Sie bei großen Typen es im Allgemeinen vorziehen, Referenzen zu übergeben, um das Kopieren zu vermeiden, wird dies im Allgemeinen nicht als schwerwiegender Schlag angesehen :)

Es gibt jedoch eine wichtige Konsequenz: Wenn Sie in Java oder C # ein Objekt an eine Methode übergeben, wissen Sie nicht, ob Ihr Objekt von der Methode geändert wird oder nicht. Es erschwert das Debuggen / Parallelisieren, und dies ist das Problem, das Functional Languages ​​und die Transparential Referency zu lösen versuchen -> Kopieren ist nicht so schlimm (wenn es Sinn macht).

Matthieu M.
quelle
-1

Die Antwort ist im Namen (na ja, fast sowieso). Eine Referenz (wie eine Adresse) verweist nur auf etwas anderes, ein Wert ist eine weitere Kopie von etwas anderem. Ich bin sicher, jemand hat wahrscheinlich etwas zu dem folgenden Effekt erwähnt, aber es wird Umstände geben, in denen einer und nicht der andere geeignet ist (Speichersicherheit vs. Speichereffizienz). Alles dreht sich um die Verwaltung von Speicher, Gedächtnis, Gedächtnis ...... SPEICHER! : D

Dunkler Stern1
quelle
-2

Okay, ich sage nicht, dass dies genau der Grund ist, warum Objekte Referenztypen sind oder als Referenz übergeben werden, aber ich kann Ihnen ein Beispiel geben, warum dies auf lange Sicht eine sehr gute Idee ist.

Wenn Sie eine Klasse in C ++ erben, werden alle Methoden und Eigenschaften dieser Klasse physisch in die untergeordnete Klasse kopiert. Es wäre, als würde man den Inhalt dieser Klasse wieder in die Kinderklasse schreiben.

Dies bedeutet, dass die Gesamtgröße der Daten in Ihrer untergeordneten Klasse eine Kombination aus dem Inhalt der übergeordneten Klasse und der abgeleiteten Klasse ist.

EG: #include

class Top 
{   
    int arrTop[20] = {1,2,3,4,5,6,7,8,9,9,8,7,6,5,4,3,2,1};
};  

class Middle : Top 
{   
    int arrMiddle[20] = {1,2,3,4,5,6,7,8,9,9,8,7,6,5,4,3,2,1};
};  

class Bottom : Middle
{   
    int arrBottom[20] = {1,2,3,4,5,6,7,8,9,9,8,7,6,5,4,3,2,1};
};  

int main()
{   
    using namespace std;

    int arr[20];
    cout << "Size of array of 20 ints: " << sizeof(arr) << endl;

    Top top;
    Middle middle;
    Bottom bottom;

    cout << "Size of Top Class: " << sizeof(top) << endl;
    cout << "Size of middle Class: " << sizeof(middle) << endl;
    cout << "Size of bottom Class: " << sizeof(bottom) << endl;

}   

Welches würde Ihnen zeigen:

Size of array of 20 ints: 80
Size of Top Class: 80
Size of middle Class: 160
Size of bottom Class: 240

Dies bedeutet, dass bei einer großen Hierarchie mehrerer Klassen die hier angegebene Gesamtgröße des Objekts die Kombination aller dieser Klassen ist. Offensichtlich wären diese Objekte in vielen Fällen beträchtlich groß.

Ich glaube, die Lösung besteht darin, sie auf dem Haufen zu erstellen und Zeiger zu verwenden. Dies bedeutet, dass die Größe von Objekten in Klassen mit mehreren Elternteilen in gewissem Sinne überschaubar wäre.

Aus diesem Grund ist die Verwendung von Referenzen eine bessere Methode, um dies zu tun.

Dhaval Anjaria
quelle
1
Dies scheint nichts Wesentliches zu bieten über Punkte, die in 13 vorherigen Antworten gemacht und erklärt wurden
Mücke