"Slicing" ist, wo ordnen Sie ein Objekt einer abgeleiteten Klasse an eine Instanz der Basisklasse, und verliert dadurch einen Teil des Informationen - auch einige "Scheiben" entfernt.
Beispielsweise
class A {int foo;};class B :public A {int bar;};
Also ein Objekt vom Typ B hat zwei Daten-member, foo und bar.
Dann, wenn Sie schreiben:
B b;
A a = b;
Dann die Informationen in b über den bar verloren in a.
Sehr informativ, aber zu sehen, stackoverflow.com/questions/274626#274636 für ein Beispiel, wie slicing Auftritt, während die Methode Aufrufe (die Unterstriche die Gefahr ein wenig besser als der gewöhnliche Zuweisung-Beispiel). Interessant. Ich habe die Programmierung in C++ für 15 Jahre und dieses Problem nie aufgetreten zu mir, da habe ich immer bestanden-Objekte per Referenz als eine Frage der Effizienz und den persönlichen Stil. Geht um zu zeigen, wie gute Gewohnheiten, die Ihnen helfen können. Vielen Dank, aber ich glaube nicht, dass casting-zurück (da keine Zeiger-Arithmetik), A a = b;a ist nun Objekt des Typs A die Kopie B::foo. Es werden Fehler warf ihn zurück jetzt, denke ich. Das ist nicht "aufschneiden", oder zumindest eine gutartige Variante. Das eigentliche problem tritt auf, wenn Sie B b1; B b2; A& b2_ref = b2; b2 = b1. Sie denken vielleicht, dass Sie kopiert haben b1 zu b2, aber Sie noch nicht! Sie kopiert ein Teilb1 zu b2 (der Teil der b1 dass B geerbt von A), und Links die anderen Teile b2 unverändert. b2 ist jetzt ein frankensteinian Kreatur, bestehend aus ein paar bits von b1 gefolgt von einige Stücke von b2. Pfui! Downvoting, weil ich denke, die Antwort ist sehr missleading. Ihren Kommentar Lesen sollten B b1; B b2; A& b2_ref = b2; b2_ref = b1 "Das eigentliche problem tritt auf, wenn Sie" ... eine Ableitung von einer Klasse mit einem nicht-virtueller Zuweisungsoperator. Ist A auch bestimmt für die Ableitung? Es hat keine virtuellen Funktionen. Wenn Sie eine Ableitung von einer Art, die man sich mit der Tatsache, dass seine member-Funktionen aufgerufen werden können!
Meisten Antworten hier ausfallen zu erklären was das eigentliche problem mit dem schneiden ist. Sie erklären den gutartigen Fällen von schneiden, nicht von der tückischen lieben. Davon aus, wie die anderen Antworten auch, dass man es mit zwei Klassen A und B, wo B leitet (öffentlich) aus A.
In dieser situation, In C++ können Sie übergeben Sie eine Instanz von B zu A's Zuweisungsoperator und der copy-Konstruktor). Dies funktioniert, da eine Instanz von B umgewandelt werden können, um eine const A&, was Operatoren und copy-Konstruktoren erwarten, dass Ihre Argumente zu sein.
Den gutartigen Fall
B b;
A a = b;
Nichts schlimmes passiert es - Sie fragte, für eine Instanz von A das eine Kopie von B, und das ist genau das, was Sie bekommen. Sicher, a nicht enthalten einige der b's Mitglieder, aber wie sollte es auch? Es ist ein A, nachdem alle, nicht ein B, also es hat noch nicht einmal gehört über diese Mitglieder, geschweige denn, Sie würde in der Lage sein, um Sie zu speichern.
Die tückischen Falle
B b1;
B b2;
A& a_ref = b2;
a_ref = b1;//b2 now contains a mixture of b1 and b2!
Könnte man denken, dass b2 wird eine Kopie der b1 danach. Aber, ach, es ist nicht! Wenn Sie untersuchen, werden Sie feststellen, dass b2 ist ein Frankensteinian Kreatur, aus einige Stücke von b1 (die Brocken, die B erbt von A), und einige Stücke von b2 (die Brocken, die nur B enthält). AUA!
Was ist passiert? Gut, C++ standardmäßig nicht behandeln Zuweisungsoperatoren als virtual. So, die Zeile a_ref = b1 ruft den Zuweisungsoperator der A nicht, dass der B. Dies ist, weil für nicht-virtuelle Funktionen, die erklärt Typ (der A&) legt fest, welche Funktion aufgerufen wird, im Gegensatz zu den tatsächlichen geben (das wäre B, da a_ref referenziert eine Instanz von B). Jetzt A's Zuweisungsoperator weiß offensichtlich nur über die Mitglieder erklärten in A, so wird es kopiert nur die, verlassen die Mitglieder Hinzugefügt B unverändert.
Lösung
Zuweisung nur auf Teile eines Objekts in der Regel wenig Sinn macht, aber C++ leider bietet keine integrierte Möglichkeit, dies verbieten. Sie können jedoch Rollen Sie Ihre eigenen. Der erste Schritt ist die Herstellung der Zuweisungsoperator virtuellen. Dies wird garantieren, dass es immer die tatsächlichen Typ ist ein Zuweisungsoperator, das heißt, nicht die erklärt geben. Der zweite Schritt ist die Verwendung dynamic_cast um zu überprüfen, dass das zugewiesene Objekt hat einen kompatiblen Typ. Der Dritte Schritt ist, um die tatsächliche Zuordnung in eine (geschützte!) Mitglied assign(), da B's assign() vielleicht A's assign() kopieren A's Mitglieder.
class A {public:virtual A&operator=(const A& a){
assign(a);return*this;}protected:void assign(const A& a){//copy members of A from a to this}};class B :public A {public:virtual B&operator=(const A& a){if(const B* b =dynamic_cast<const B*>(&a))
assign(*b);elsethrow bad_assignment();return*this;}protected:void assign(const B& b){
A::assign(b);//Let A's assign() copy members of A from b to this//copy members of B from b to this}};
Beachten Sie, dass für Reine Bequemlichkeit, B's operator= covariantly überschreibt die zurück geben, da es weiß, dass es die Rückgabe einer Instanz von B.
IMHO, das problem ist, dass es zwei verschiedene Arten von Ersetzbarkeit, die möglicherweise implizit durch Vererbung: entweder derived Wert gegeben werden können, um code zu erwarten, ein base Wert, oder abgeleitete Referenz verwendet werden kann als Basis-Referenz. Ich würde gerne sehen, eine Sprache mit einer Art system, die Adressen der beiden Konzepte getrennt. Es gibt viele Fälle, in denen eine abgeleitete Referenz sollte substituierbar für eine Basis-Referenz, aber abgeleitet, die Instanzen sollten nicht substituierbar für die Basis; es gibt auch viele Fälle, in denen Instanzen werden sollte, Cabrio, aber die Referenzen sollten nicht als Ersatz. Ich verstehe nicht, was ist so schlecht in Ihre "verräterischen" der Fall. Sie haben angegeben, dass Sie möchten, um: 1) eine Referenz auf ein Objekt der Klasse A und 2) CASTET das Objekt b1 der Klasse A und eine Kopie der Bestellung an einen Referenz der Klasse A. Was ist eigentlich falsch hier ist die richtige Logik hinter dem angegebenen code. In anderen Worten, Sie nahm einen kleinen Bilderrahmen (A), platziert es über ein größeres Bild (B) und Sie Malte über, Rahmen, beschweren sich später, dass Ihr das größere Bild sieht jetzt hässlich 🙂 Aber wenn wir nur Bedenken, dass gerahmten Bereich, es sieht ziemlich gut, wie der Maler wollte, richtig? 🙂 Das problem ist, anders ausgedrückt, dass in C++ standardmäßig übernimmt eine sehr starke Art von Ersetzbarkeit - es erfordert die Basis-Klasse ' Operationen zu workly richtig auf Unterklasse-Instanzen. Und das sogar für Operationen, die der compiler automatisch generierten wie die Abtretung mitteilt. Es ist also nicht genug, um nicht vermasseln Ihre eigenen Aktivitäten in dieser Hinsicht, Sie haben auch explizit deaktivieren der falsche, der vom compiler erzeugt. Oder natürlich, bleiben Sie Weg von öffentlicher Vererbung, die in der Regel ist ein guter Vorschlag überhaupt 😉 Ein weiterer gemeinsamer Ansatz ist, einfach deaktivieren Sie die copy-und Zuweisungsoperator. Für die Klassen innerhalb der Vererbungshierarchie, in der Regel gibt es keinen Grund für die Verwendung von value, anstatt Referenz oder ein Zeiger. Was das? Ich hatte keine Ahnung, Operatoren markiert werden können virtuellen
Wenn Sie eine Basis-Klasse A und eine abgeleitete Klasse B, dann können Sie das folgende tun.
void wantAnA(A myA){//work with myA}
B derived;//work with the object "derived"
wantAnA(derived);
Nun die Methode wantAnA muss eine Kopie der derived. Jedoch, das Objekt derived kann nicht kopiert werden völlig, wie die Klasse B erfinden könnte, zusätzliche member-Variablen, die nicht in Ihrer Basis-Klasse A.
Daher, zu nennen wantAnA, der compiler "schneiden" alle weiteren Mitglieder der abgeleiteten Klasse. Das Ergebnis könnte ein Objekt sein, das Sie nicht wollen, zu erstellen, weil
es mag unvollkommen sein,
es verhält sich wie ein A-Objekt (alle spezielle Verhalten der Klasse B verloren gegangen ist).
C++ ist nicht Java! Wenn wantAnA (wie der name schon sagt!) will ein A haben, dann ist das, was es bekommt. Und eine Instanz von A, wird sich, äh, Verhalten sich wie ein A. Wie ist das überraschend? Es ist überraschend, weil Sie don ' T pass ein, um die Funktion. Das Verhalten ist ähnlich. Aber der Durchschnittliche C++ - Programmierer ist es vielleicht weniger offensichtlich. Soweit ich verstanden die Frage ist niemand "beschwert". Es geht nur darum, wie der compiler verarbeitet die situation. Imho ist es besser, zu vermeiden, schneiden durch Weitergabe (const) Referenzen. Nein, ich würde nicht werfen, erbschaft, sondern Referenzen verwenden. Wenn die Signatur von wantAnA void wantAnA(const A & myA), dann gab es nicht schneiden. Stattdessen ein read-only Referenz auf das aufrufende Objekt übergeben. das problem ist vor allem auf die automatische Typumwandlung, die vom compiler führt aus derived auf die Art A. Implizite Typumwandlung ist immer wieder eine Quelle von unerwarteten Verhalten in C++, weil es oft schwer zu verstehen, vom Blick auf den code lokal, dass eine Besetzung stattgefunden hat.
Diese sind alle gute Antworten. Ich möchte nur hinzufügen, eine Ausführung Beispiel bei der übergabe von Objekten per value vs Verweis:
#include<iostream>usingnamespace std;//Base classclass A {public:
A(){}
A(const A& a){
cout <<"'A' copy constructor"<< endl;}virtualvoid run()const{ cout <<"I am an 'A'"<< endl;}};//Derived classclass B:public A {public:
B():A(){}
B(const B& a):A(a){
cout <<"'B' copy constructor"<< endl;}virtualvoid run()const{ cout <<"I am a 'B'"<< endl;}};void g(const A & a){
a.run();}void h(const A a){
a.run();}int main(){
cout <<"Call by reference"<< endl;
g(B());
cout << endl <<"Call by copy"<< endl;
h(B());}
Ausgabe:
Call by reference
I am a 'B'Call by copy
'A' copy constructor
I am an 'A'
Das ist die einfachste Lösung, um zu vermeiden, Objekt, schneiden, +1. Gutes Beispiel, +1. Hallo. Super Antwort, aber ich habe eine Frage. Wenn ich etwas mache, wie diese ** dev d; base* b = &d;** Das aufschneiden der auch stattfindet?
Es ist also bei der Zuweisung eines Objekts einer Unterklasse der Superklasse. Die Oberklasse weiß nichts von der zusätzlichen Informationen, die in der Unterklasse, und hat nicht Raum, um es zu speichern, so dass die zusätzliche information wird "abgeschnitten".
Wenn diese links geben nicht genug Informationen für eine "gute Antwort" bitte Bearbeiten Sie die Frage, lassen Sie uns wissen, was Sie suchen.
Dem slicing-problem ist ernst, denn es kann zu einer Speicherbeschädigung führen, und es ist sehr schwierig zu garantieren, ein Programm nicht darunter leiden. Das design aus der Sprache, Klassen, Vererbung zugänglich sein sollen nur als Referenz (nicht als Wert). Die D-Programmiersprache besitzt diese Eigenschaft.
Überlegen, Klasse A, und Klasse B, abgeleitet von A. Speicher Korruption kann passieren, wenn der Eine Teil hat einen Zeiger p und eine B-Instanz, die Punkte p zu B zusätzliche Daten. Dann, wenn die zusätzlichen Daten wird abgeschnitten, p verweist Müll.
Bitte erläutern Sie, wie die Beschädigung des Speichers kommen kann. Aufruf von foo() ruft A::foo() nach aufschneiden, nicht B::foo() ... Ich habe vergessen, dass die copy-ctor setzt den vptr, mein Fehler. Aber können Sie immer noch beschädigt ist, wenn a Eine pointer-und B-sets, dass zu Punkt B Abschnitt wird geschnitten aus. Dieses problem beschränkt sich nicht nur auf schneiden. Alle Klassen enthalten, die Zeiger sind haben unseriöse Verhalten mit einem Standard-Zuweisungsoperator und copy-Konstruktor. Was macht object slicing schlimmer als eine Allgemeine pointer-Korrekturen ist, dass Sie sicher, Sie haben verhindert, schneiden von Ereignis, eine Basisklasse muss die Umwandlung Konstruktoren für jede abgeleitete Klasse. (Warum? Alle abgeleiteten Klassen, die fehlen, sind anfällig für Abholung von der Basis-Klasse " copy ctor, da Derived implizit konvertierbar Base.) Dies ist offensichtlich gegen die Offen-Geschlossen-Prinzip, und eine große Bürde der Wartung.
In C++ eine abgeleitete Klasse object zugewiesen werden kann, ein Basis-Objekt-Klasse, aber der andere Weg ist nicht möglich.
classBase{int x, y;};classDerived:publicBase{int z, w;};int main(){Derived d;Base b = d;//Object Slicing, z and w of d are sliced off}
Objekt slicing passiert, wenn eine abgeleitete Klasse-Objekt zugewiesen ist, auf ein Basis-Objekt-Klasse, die zusätzlichen Attribute der abgeleiteten Klasse ein Objekt geschnitten aus, bilden die Basisklasse object.
Also ... Warum verliert der abgeleitete Informationen schlecht? ... weil der Autor der abgeleiteten Klasse kann verändert die Darstellung so, dass Sie schneiden Sie die zusätzlichen Informationen, ändert sich der Wert, repräsentiert durch das Objekt. Dies kann passieren, wenn die abgeleitete Klasse, wenn verwendet, um cache-Darstellung, die effizienter ist für bestimmte Operationen, aber teuer zu transformieren zurück an die Basis-Darstellung.
Dachte auch, jemand sollte auch erwähnen, was Sie tun sollten, um zu vermeiden, schneiden...
Holen Sie sich eine Kopie von C++ Coding Standards, 101 Regeln, Richtlinien und best practices. Umgang mit slicing #54.
Er schlägt eine etwas anspruchsvollere Muster zu voll befassen sich mit der Frage: haben Sie eine geschützte Kopie-Konstruktor, einem geschützten reinen virtuellen DoClone, und eine öffentliche Clone mit einem geltend machen, die Ihnen sagen, wenn eine (weitere) abgeleitete Klasse umgesetzt DoClone richtig. (Die Clone-Methode macht eine richtige Tiefe Kopie des polymorphen Objekt.)
Können Sie auch markieren Sie den copy-Konstruktor auf der Basis expliziten, das ermöglicht der explizite schneiden, wenn es erwünscht ist.
"Sie können auch markieren Sie den copy-Konstruktor auf der Basis explicit", die nicht Hilfe an alle.
Dem slicing-problem in C++ ergibt sich aus dem Wert der Semantik der Objekte, die blieb vor allem aufgrund der Kompatibilität mit C-structs. Sie müssen verwenden Sie die explizite Referenz oder ein Zeiger-syntax zu erreichen, die "normalen" Objekt-Verhalten in den meisten anderen Sprachen, die Objekte, d.h. Objekte werden immer übergeben nach Verweis.
Die kurzen Antworten ist, dass Sie schneiden das Objekt durch die Zuordnung eines abgeleiteten Objekts zu einem base-Objekt von Wert, d.h. die verbleibenden Objekt ist nur ein Teil des abgeleiteten Objekts. Um die zu erhalten Wert-Semantik, slicing ist ein vernünftiges Verhalten und hat seine relativ selten verwendet, das existiert nicht in den meisten anderen Sprachen. Einige Menschen halten es für ein feature von C++, während viele hielt es für eine der Macken/misfeatures von C++.
""normalen" Objekt-Verhalten" das ist nicht "normal-Objekt Verhalten", das ist semantische Referenz. Und es bezieht sich in keiner Weise mit C struct -, Kompatibilitäts-oder anderen, nicht-Sinn, der in jeder x-beliebigen OOP Priester sagte Sie. Amen, Bruder. Es ist traurig zu sehen, wie oft C++ bashed von nicht Java, wenn Wert-Semantik ist eines der Dinge, die das C++ so wahnsinnig mächtig. Dies ist nicht eine Funktion, nicht eine Macke/misfeature. Es ist normal, on-stack kopieren von Verhalten, da Sie eine Funktion aufrufen, die mit einem arg oder (gleiche) Zuteilung von stack-variable vom Typ Base muss genau sizeof(Base) bytes im Speicher, mit möglichen Ausrichtung, vielleicht, das ist, warum "Zuordnung" (on-stack-Kopie) keine Kopie der abgeleiteten Klasse Mitglieder, deren offsets liegen außerhalb sizeof. Um zu vermeiden, "Verlust von Daten", nur mit Mauszeiger, wie jeder andere auch, da-Zeiger-Speicher ist fixiert, und die Größe, in der Erwägung, dass stack ist sehr volitile Definitiv ein misfeature von C++. Die Zuordnung eines abgeleiteten Objekts zu einem base-Objekt sollte verboten werden, während die Bindung ein abgeleitetes Objekt eine Referenz oder einen Zeiger der Basisklasse sollte in Ordnung sein.
In diesem Fall werden keine Daten der Mitglieder oder member-Funktionen der dynamischen Variablen
wird darauf von ptrD (Nachfahren der Klasse object) verloren. Darüber hinaus, wenn Sie Funktionen verwenden zu können, muss die Funktion sein, die eine virtuelle Funktion.
Ich verstehe das "slicing" - Teil, aber ich verstehe nicht "problem". Wie ist es ein problem, dass einige Zustand dog das ist nicht Bestandteil der Klasse Pet (die breed Daten-Mitglied) ist nicht kopiert, der in der Variablen pet? Der code ist nur daran interessiert ist, die Pet Mitglieder-Daten - scheinbar. Slicing ist definitiv ein "problem", wenn es unerwünscht ist, aber ich sehe nicht, dass hier. "((Dog *)ptrP)" Ich schlage vor, mit static_cast<Dog*>(ptrP) Ich schlage vor, wies darauf hin, dass Sie in der string 'Rasse' schließlich Speicherverlust ohne virtuellen Destruktor (destructor 'string' wird nicht aufgerufen), wenn das löschen durch 'ptrP'... Warum ist das, was Sie zeigen problematisch? Die Lösung ist meist die richtige Klasse design. Das problem in diesem Fall ist, dass nieder zu schreiben Konstruktoren um die Sichtbarkeit zu Steuern beim vererben ist langweilig und schnell vergessen. Sie bekommen nicht überall in der Nähe der Gefahrenzone mit Ihrem code, da es keine Polymorphismus beteiligt ist oder auch nur erwähnt (aufschneiden, schneidet Ihr Objekt aber nicht, dass das Programm abstürzt, hier). -1 Dies nicht ganz zu erklären ist das eigentliche problem. C++ hat den Wert-Semantik, nicht Referenz-Semantik wie Java, so ist dies alles durchaus zu erwarten. Und der "fix" ist wirklich ein Beispiel von wirklich schrecklich C++ - code. "Fixierung" nicht vorhandene Probleme, wie diese Art des Schneidens durch den Rückgriff auf die dynamische Zuordnung ist ein Rezept für buggy-code, Speicherbelegung und schreckliche Leistung. Beachten Sie, dass es in Fällen, in denen schneiden ist schlecht, aber diese Antwort fehlschlägt, darauf hinzuweisen. Hinweis: der ärger beginnt, wenn Sie ordnen Sie über Referenzen. Tun Sie auch verstehen, dass der Versuch, Zugriff auf member des Typs, der nicht definiert ist (Dog::breed) ist in keiner Weise ein FEHLER mit Bezug zu SCHNEIDEN?
Scheint es mir, dass die schneiden nicht so sehr ein problem der anderen, als wenn Sie Ihre eigenen Klassen und Programm sind schlecht konzipiert/entwickelt.
Wenn ich vorbeigehe, ein Unterklasse-Objekt als parameter an eine Methode, die einen parameter vom Typ Oberklasse, ich sollte sicherlich bewusst sein und wissen, die intern aufgerufene Methode arbeitet mit der Oberklasse (aka baseclass) Objekt nur.
Mir scheint es nur die unvernünftige Erwartung, dass die Bereitstellung einer Unterklasse, wo eine baseclass angefordert wird, würde irgendwie das Ergebnis in der Unterklasse, bestimmte Ergebnisse, würde dazu führen, schneiden ein problem zu sein. Die schlechte Gestaltung in der Nutzung der Methode oder eine Arme Unterklasse Umsetzung. Ich vermute, es ist in der Regel das Ergebnis von opfern, gute OOP-design zu Gunsten der Zweckmäßigkeit oder der performance-Gewinne.
Aber denken Sie daran, Minok, dass Sie sich NICHT übergeben eine Referenz des Objekts. Sie sind vorbei, eine NEUE Kopie des Objekts, sondern mit dem base-Klasse zu kopieren, es in den Prozess. geschützt kopieren/Zuweisung auf der Basis der Klasse und das problem ist gelöst. Du hast Recht. Gute Praxis ist die Verwendung von abstrakten Basisklassen oder zu beschränken, die Zugang zu Kopier - /Abtretung. Jedoch, es ist nicht so leicht zu erkennen, sobald es da ist und einfach zu vergessen, zu kümmern. Aufruf von virtuellen Methoden mit in Scheiben geschnitten *dadurch kann die mysteriösen Dinge passieren, wenn Sie Weg, ohne eine Zugriffsverletzung. Ich erinnere mich aus meiner C++ - Programmierung Kurse in der Universität, es standen best practices, die wir für jede Klasse erstellt, wir waren erforderlich, um zu schreiben, Standard-Konstruktoren, copy-Konstruktoren und Zuweisungsoperatoren, sowie einen Destruktor. Auf diese Weise haben Sie sichergestellt, dass die Kopie-Konstruktion und dergleichen geschah so, wie Sie es benötigt, ist beim schreiben der Klasse... anstatt später auf ein seltsames Verhalten zeigt.
Slicing bedeutet, dass die Daten Hinzugefügt werden, indem eine Unterklasse werden verworfen, wenn ein Objekt der Unterklasse übergeben oder zurückgegeben wird, durch einen Wert oder eine Funktion erwartet ein Objekt Basisklasse.
Erklärung:
Betrachten Sie die folgende Klassendeklaration:
Als baseclass kopieren Sie Funktionen, die nicht wissen, etwas über die abgeleiteten nur der Basis-Teil der abgeleiteten kopiert wird. Dies wird gemeinhin als schneiden.
class A
{int x;};class B
{
B(): x(1), c('a'){}int x;char c;};int main(){
A a;
B b;
a = b;//b.c == 'a' is "sliced" offreturn0;}
Würden Sie mir, mit einigen zusätzlichen details? Wie sieht Ihre Antwort unterscheiden sich von den schon gepostet? Ich denke, mehr Erklärung wäre nicht schlecht.
wenn eine abgeleitete Klasse-Objekt zugewiesen ist, auf ein Basis-Objekt-Klasse, die zusätzlichen Attribute der abgeleiteten Klasse ein Objekt werden abgeschnitten (verwerfen) bilden die Basisklasse object.
classBase{int x;};classDerived:publicBase{int z;};int main(){Derived d;Base b = d;//Object Slicing, z of d is sliced off}
Wenn eine Abgeleitete Klasse Objekt zugeordnet ist Basis-Objekt-Klasse, die für alle Mitglieder der abgeleiteten Klasse ein Objekt wird kopiert-Basis-Klasse-Objekt, mit Ausnahme der Mitglieder, die nicht anwesend sind in der base-Klasse. Diese Mitglieder werden in Scheiben Geschnitten Weg durch den compiler.
Dies wird als Objekt Schneiden.
[Error]'class Base' has no member named 'd'[Error]'class Base' has no member named 'e'
Downvoted weil das ist kein gutes Beispiel. Es würde nicht funktionieren, wenn anstelle von kopieren von d auf b, verwenden Sie einen Zeiger, in diesem Fall d und e noch existieren würde, aber Base muss nicht die Mitglieder. Dein Beispiel zeigt nur, dass Sie nicht zugreifen können Mitglieder, die die Klasse nicht haben.
Ich rannte über die slicing-problem und prompt hier gelandet. So lassen Sie mich hinzufügen meine zwei Cent auf diese.
Wir haben ein Beispiel aus der "production code" (oder etwas, das kommt irgendwie in der Nähe):
Sagen wir, wir haben etwas, das löst Aktionen. Ein control center UI zum Beispiel.
Das UI braucht, um eine Liste der Dinge, die derzeit in der Lage zu sein, ausgelöst wird. So definieren wir eine Klasse, die enthält die Versand-Informationen. Nennen wir es Action. So ein Action hat einige member-Variablen. Für die Einfachheit, die wir gerade haben 2, ein std::string name und ein std::function<void()> f. Dann hat Sie ein void activate() die gerade führt die f Mitglied.
Also die UI bekommt ein std::vector<Action> geliefert. Mir vorstellen, dass einige Funktionen wie z.B.:
void push_back(Action toAdd);
Nun haben wir festgestellt, wie sieht es aus UI-Perspektive. Kein problem so weit. Aber einige andere Kerl, der arbeitet an diesem Projekt plötzlich entscheidet, dass es spezielle Aktionen, die mehr Informationen benötigen, die Action Objekt. Aus welchem Grund auch immer. Das könnte auch gelöst werden, mit lambda, erfasst. Dieses Beispiel ist nicht 1-1 aus dem code.
Also der Typ leitet sich von Action auf seinen eigenen Geschmack.
Er übergibt eine Instanz von seinem home-brewed-Klasse auf den push_back dann aber das Programm geht drunter und drüber.
Also, was ist passiert?
Als Sie könnte erraten haben: das Objekt wurde in Scheiben geschnitten.
Den zusätzlichen Informationen aus der Instanz verloren wurde, und f ist jetzt anfällig für Undefiniertes Verhalten.
Ich hoffe dieses Beispiel bringt Licht etwa für jene Leute, die können nicht wirklich vorstellen, wie die Dinge, wenn Sie darüber reden As und Bs abgeleitet wird, in irgendeiner Weise.
"Slicing" ist, wo ordnen Sie ein Objekt einer abgeleiteten Klasse an eine Instanz der Basisklasse, und verliert dadurch einen Teil des Informationen - auch einige "Scheiben" entfernt.
Beispielsweise
Also ein Objekt vom Typ
B
hat zwei Daten-member,foo
undbar
.Dann, wenn Sie schreiben:
Dann die Informationen in
b
über denbar
verloren ina
.Interessant. Ich habe die Programmierung in C++ für 15 Jahre und dieses Problem nie aufgetreten zu mir, da habe ich immer bestanden-Objekte per Referenz als eine Frage der Effizienz und den persönlichen Stil. Geht um zu zeigen, wie gute Gewohnheiten, die Ihnen helfen können.
Vielen Dank, aber ich glaube nicht, dass casting-zurück (da keine Zeiger-Arithmetik),
A a = b;
a
ist nun Objekt des TypsA
die KopieB::foo
. Es werden Fehler warf ihn zurück jetzt, denke ich.Das ist nicht "aufschneiden", oder zumindest eine gutartige Variante. Das eigentliche problem tritt auf, wenn Sie
B b1; B b2; A& b2_ref = b2; b2 = b1
. Sie denken vielleicht, dass Sie kopiert habenb1
zub2
, aber Sie noch nicht! Sie kopiert ein Teilb1
zub2
(der Teil derb1
dassB
geerbt vonA
), und Links die anderen Teileb2
unverändert.b2
ist jetzt ein frankensteinian Kreatur, bestehend aus ein paar bits vonb1
gefolgt von einige Stücke vonb2
. Pfui! Downvoting, weil ich denke, die Antwort ist sehr missleading.Ihren Kommentar Lesen sollten
B b1; B b2; A& b2_ref = b2; b2_ref = b1
"Das eigentliche problem tritt auf, wenn Sie" ... eine Ableitung von einer Klasse mit einem nicht-virtueller Zuweisungsoperator. IstA
auch bestimmt für die Ableitung? Es hat keine virtuellen Funktionen. Wenn Sie eine Ableitung von einer Art, die man sich mit der Tatsache, dass seine member-Funktionen aufgerufen werden können!InformationsquelleAutor David Dibben
Meisten Antworten hier ausfallen zu erklären was das eigentliche problem mit dem schneiden ist. Sie erklären den gutartigen Fällen von schneiden, nicht von der tückischen lieben. Davon aus, wie die anderen Antworten auch, dass man es mit zwei Klassen
A
undB
, woB
leitet (öffentlich) ausA
.In dieser situation, In C++ können Sie übergeben Sie eine Instanz von
B
zuA
's Zuweisungsoperator und der copy-Konstruktor). Dies funktioniert, da eine Instanz vonB
umgewandelt werden können, um eineconst A&
, was Operatoren und copy-Konstruktoren erwarten, dass Ihre Argumente zu sein.Den gutartigen Fall
Nichts schlimmes passiert es - Sie fragte, für eine Instanz von
A
das eine Kopie vonB
, und das ist genau das, was Sie bekommen. Sicher,a
nicht enthalten einige derb
's Mitglieder, aber wie sollte es auch? Es ist einA
, nachdem alle, nicht einB
, also es hat noch nicht einmal gehört über diese Mitglieder, geschweige denn, Sie würde in der Lage sein, um Sie zu speichern.Die tückischen Falle
Könnte man denken, dass
b2
wird eine Kopie derb1
danach. Aber, ach, es ist nicht! Wenn Sie untersuchen, werden Sie feststellen, dassb2
ist ein Frankensteinian Kreatur, aus einige Stücke vonb1
(die Brocken, dieB
erbt vonA
), und einige Stücke vonb2
(die Brocken, die nurB
enthält). AUA!Was ist passiert? Gut, C++ standardmäßig nicht behandeln Zuweisungsoperatoren als
virtual
. So, die Zeilea_ref = b1
ruft den Zuweisungsoperator derA
nicht, dass derB
. Dies ist, weil für nicht-virtuelle Funktionen, die erklärt Typ (derA&
) legt fest, welche Funktion aufgerufen wird, im Gegensatz zu den tatsächlichen geben (das wäreB
, daa_ref
referenziert eine Instanz vonB
). JetztA
's Zuweisungsoperator weiß offensichtlich nur über die Mitglieder erklärten inA
, so wird es kopiert nur die, verlassen die Mitglieder HinzugefügtB
unverändert.Lösung
Zuweisung nur auf Teile eines Objekts in der Regel wenig Sinn macht, aber C++ leider bietet keine integrierte Möglichkeit, dies verbieten. Sie können jedoch Rollen Sie Ihre eigenen. Der erste Schritt ist die Herstellung der Zuweisungsoperator virtuellen. Dies wird garantieren, dass es immer die tatsächlichen Typ ist ein Zuweisungsoperator, das heißt, nicht die erklärt geben. Der zweite Schritt ist die Verwendung
dynamic_cast
um zu überprüfen, dass das zugewiesene Objekt hat einen kompatiblen Typ. Der Dritte Schritt ist, um die tatsächliche Zuordnung in eine (geschützte!) Mitgliedassign()
, daB
'sassign()
vielleichtA
'sassign()
kopierenA
's Mitglieder.Beachten Sie, dass für Reine Bequemlichkeit,
B
'soperator=
covariantly überschreibt die zurück geben, da es weiß, dass es die Rückgabe einer Instanz vonB
.derived
Wert gegeben werden können, um code zu erwarten, einbase
Wert, oder abgeleitete Referenz verwendet werden kann als Basis-Referenz. Ich würde gerne sehen, eine Sprache mit einer Art system, die Adressen der beiden Konzepte getrennt. Es gibt viele Fälle, in denen eine abgeleitete Referenz sollte substituierbar für eine Basis-Referenz, aber abgeleitet, die Instanzen sollten nicht substituierbar für die Basis; es gibt auch viele Fälle, in denen Instanzen werden sollte, Cabrio, aber die Referenzen sollten nicht als Ersatz.Ich verstehe nicht, was ist so schlecht in Ihre "verräterischen" der Fall. Sie haben angegeben, dass Sie möchten, um: 1) eine Referenz auf ein Objekt der Klasse A und 2) CASTET das Objekt b1 der Klasse A und eine Kopie der Bestellung an einen Referenz der Klasse A. Was ist eigentlich falsch hier ist die richtige Logik hinter dem angegebenen code. In anderen Worten, Sie nahm einen kleinen Bilderrahmen (A), platziert es über ein größeres Bild (B) und Sie Malte über, Rahmen, beschweren sich später, dass Ihr das größere Bild sieht jetzt hässlich 🙂 Aber wenn wir nur Bedenken, dass gerahmten Bereich, es sieht ziemlich gut, wie der Maler wollte, richtig? 🙂
Das problem ist, anders ausgedrückt, dass in C++ standardmäßig übernimmt eine sehr starke Art von Ersetzbarkeit - es erfordert die Basis-Klasse ' Operationen zu workly richtig auf Unterklasse-Instanzen. Und das sogar für Operationen, die der compiler automatisch generierten wie die Abtretung mitteilt. Es ist also nicht genug, um nicht vermasseln Ihre eigenen Aktivitäten in dieser Hinsicht, Sie haben auch explizit deaktivieren der falsche, der vom compiler erzeugt. Oder natürlich, bleiben Sie Weg von öffentlicher Vererbung, die in der Regel ist ein guter Vorschlag überhaupt 😉
Ein weiterer gemeinsamer Ansatz ist, einfach deaktivieren Sie die copy-und Zuweisungsoperator. Für die Klassen innerhalb der Vererbungshierarchie, in der Regel gibt es keinen Grund für die Verwendung von value, anstatt Referenz oder ein Zeiger.
Was das? Ich hatte keine Ahnung, Operatoren markiert werden können virtuellen
InformationsquelleAutor fgp
Wenn Sie eine Basis-Klasse
A
und eine abgeleitete KlasseB
, dann können Sie das folgende tun.Nun die Methode
wantAnA
muss eine Kopie derderived
. Jedoch, das Objektderived
kann nicht kopiert werden völlig, wie die KlasseB
erfinden könnte, zusätzliche member-Variablen, die nicht in Ihrer Basis-KlasseA
.Daher, zu nennen
wantAnA
, der compiler "schneiden" alle weiteren Mitglieder der abgeleiteten Klasse. Das Ergebnis könnte ein Objekt sein, das Sie nicht wollen, zu erstellen, weilA
-Objekt (alle spezielle Verhalten der KlasseB
verloren gegangen ist).wantAnA
(wie der name schon sagt!) will einA
haben, dann ist das, was es bekommt. Und eine Instanz vonA
, wird sich, äh, Verhalten sich wie einA
. Wie ist das überraschend?Es ist überraschend, weil Sie don ' T pass ein, um die Funktion.
Das Verhalten ist ähnlich. Aber der Durchschnittliche C++ - Programmierer ist es vielleicht weniger offensichtlich. Soweit ich verstanden die Frage ist niemand "beschwert". Es geht nur darum, wie der compiler verarbeitet die situation. Imho ist es besser, zu vermeiden, schneiden durch Weitergabe (const) Referenzen.
Nein, ich würde nicht werfen, erbschaft, sondern Referenzen verwenden. Wenn die Signatur von wantAnA void wantAnA(const A & myA), dann gab es nicht schneiden. Stattdessen ein read-only Referenz auf das aufrufende Objekt übergeben.
das problem ist vor allem auf die automatische Typumwandlung, die vom compiler führt aus
derived
auf die ArtA
. Implizite Typumwandlung ist immer wieder eine Quelle von unerwarteten Verhalten in C++, weil es oft schwer zu verstehen, vom Blick auf den code lokal, dass eine Besetzung stattgefunden hat.InformationsquelleAutor Black
Diese sind alle gute Antworten. Ich möchte nur hinzufügen, eine Ausführung Beispiel bei der übergabe von Objekten per value vs Verweis:
Ausgabe:
Gutes Beispiel, +1.
Hallo. Super Antwort, aber ich habe eine Frage. Wenn ich etwas mache, wie diese ** dev d; base* b = &d;** Das aufschneiden der auch stattfindet?
InformationsquelleAutor geh
Dritten Spiel in google nach "C++ "slicing" gibt mir dieser Wikipedia-Artikel http://en.wikipedia.org/wiki/Object_slicing und diese (beheizt, aber die ersten paar posts das problem definieren) : http://bytes.com/forum/thread163565.html
Es ist also bei der Zuweisung eines Objekts einer Unterklasse der Superklasse. Die Oberklasse weiß nichts von der zusätzlichen Informationen, die in der Unterklasse, und hat nicht Raum, um es zu speichern, so dass die zusätzliche information wird "abgeschnitten".
Wenn diese links geben nicht genug Informationen für eine "gute Antwort" bitte Bearbeiten Sie die Frage, lassen Sie uns wissen, was Sie suchen.
InformationsquelleAutor The Archetypal Paul
Dem slicing-problem ist ernst, denn es kann zu einer Speicherbeschädigung führen, und es ist sehr schwierig zu garantieren, ein Programm nicht darunter leiden. Das design aus der Sprache, Klassen, Vererbung zugänglich sein sollen nur als Referenz (nicht als Wert). Die D-Programmiersprache besitzt diese Eigenschaft.
Überlegen, Klasse A, und Klasse B, abgeleitet von A. Speicher Korruption kann passieren, wenn der Eine Teil hat einen Zeiger p und eine B-Instanz, die Punkte p zu B zusätzliche Daten. Dann, wenn die zusätzlichen Daten wird abgeschnitten, p verweist Müll.
Aufruf von foo() ruft A::foo() nach aufschneiden, nicht B::foo() ...
Ich habe vergessen, dass die copy-ctor setzt den vptr, mein Fehler. Aber können Sie immer noch beschädigt ist, wenn a Eine pointer-und B-sets, dass zu Punkt B Abschnitt wird geschnitten aus.
Dieses problem beschränkt sich nicht nur auf schneiden. Alle Klassen enthalten, die Zeiger sind haben unseriöse Verhalten mit einem Standard-Zuweisungsoperator und copy-Konstruktor.
Was macht object slicing schlimmer als eine Allgemeine pointer-Korrekturen ist, dass Sie sicher, Sie haben verhindert, schneiden von Ereignis, eine Basisklasse muss die Umwandlung Konstruktoren für jede abgeleitete Klasse. (Warum? Alle abgeleiteten Klassen, die fehlen, sind anfällig für Abholung von der Basis-Klasse " copy ctor, da
Derived
implizit konvertierbarBase
.) Dies ist offensichtlich gegen die Offen-Geschlossen-Prinzip, und eine große Bürde der Wartung.InformationsquelleAutor Walter Bright
In C++ eine abgeleitete Klasse object zugewiesen werden kann, ein Basis-Objekt-Klasse, aber der andere Weg ist nicht möglich.
Objekt slicing passiert, wenn eine abgeleitete Klasse-Objekt zugewiesen ist, auf ein Basis-Objekt-Klasse, die zusätzlichen Attribute der abgeleiteten Klasse ein Objekt geschnitten aus, bilden die Basisklasse object.
InformationsquelleAutor Kartik Maheshwari
Also ... Warum verliert der abgeleitete Informationen schlecht? ... weil der Autor der abgeleiteten Klasse kann verändert die Darstellung so, dass Sie schneiden Sie die zusätzlichen Informationen, ändert sich der Wert, repräsentiert durch das Objekt. Dies kann passieren, wenn die abgeleitete Klasse, wenn verwendet, um cache-Darstellung, die effizienter ist für bestimmte Operationen, aber teuer zu transformieren zurück an die Basis-Darstellung.
Dachte auch, jemand sollte auch erwähnen, was Sie tun sollten, um zu vermeiden, schneiden...
Holen Sie sich eine Kopie von C++ Coding Standards, 101 Regeln, Richtlinien und best practices. Umgang mit slicing #54.
Er schlägt eine etwas anspruchsvollere Muster zu voll befassen sich mit der Frage: haben Sie eine geschützte Kopie-Konstruktor, einem geschützten reinen virtuellen DoClone, und eine öffentliche Clone mit einem geltend machen, die Ihnen sagen, wenn eine (weitere) abgeleitete Klasse umgesetzt DoClone richtig. (Die Clone-Methode macht eine richtige Tiefe Kopie des polymorphen Objekt.)
Können Sie auch markieren Sie den copy-Konstruktor auf der Basis expliziten, das ermöglicht der explizite schneiden, wenn es erwünscht ist.
InformationsquelleAutor Steve Steiner
Dem slicing-problem in C++ ergibt sich aus dem Wert der Semantik der Objekte, die blieb vor allem aufgrund der Kompatibilität mit C-structs. Sie müssen verwenden Sie die explizite Referenz oder ein Zeiger-syntax zu erreichen, die "normalen" Objekt-Verhalten in den meisten anderen Sprachen, die Objekte, d.h. Objekte werden immer übergeben nach Verweis.
Die kurzen Antworten ist, dass Sie schneiden das Objekt durch die Zuordnung eines abgeleiteten Objekts zu einem base-Objekt von Wert, d.h. die verbleibenden Objekt ist nur ein Teil des abgeleiteten Objekts. Um die zu erhalten Wert-Semantik, slicing ist ein vernünftiges Verhalten und hat seine relativ selten verwendet, das existiert nicht in den meisten anderen Sprachen. Einige Menschen halten es für ein feature von C++, während viele hielt es für eine der Macken/misfeatures von C++.
struct
-, Kompatibilitäts-oder anderen, nicht-Sinn, der in jeder x-beliebigen OOP Priester sagte Sie.Amen, Bruder. Es ist traurig zu sehen, wie oft C++ bashed von nicht Java, wenn Wert-Semantik ist eines der Dinge, die das C++ so wahnsinnig mächtig.
Dies ist nicht eine Funktion, nicht eine Macke/misfeature. Es ist normal, on-stack kopieren von Verhalten, da Sie eine Funktion aufrufen, die mit einem arg oder (gleiche) Zuteilung von stack-variable vom Typ
Base
muss genausizeof(Base)
bytes im Speicher, mit möglichen Ausrichtung, vielleicht, das ist, warum "Zuordnung" (on-stack-Kopie) keine Kopie der abgeleiteten Klasse Mitglieder, deren offsets liegen außerhalb sizeof. Um zu vermeiden, "Verlust von Daten", nur mit Mauszeiger, wie jeder andere auch, da-Zeiger-Speicher ist fixiert, und die Größe, in der Erwägung, dass stack ist sehr volitileDefinitiv ein misfeature von C++. Die Zuordnung eines abgeleiteten Objekts zu einem base-Objekt sollte verboten werden, während die Bindung ein abgeleitetes Objekt eine Referenz oder einen Zeiger der Basisklasse sollte in Ordnung sein.
InformationsquelleAutor ididak
1. DIE DEFINITION VON SLICING-PROBLEM
Wenn D ist eine abgeleitete Klasse der Basisklasse B, so ordnen Sie ein Objekt der Abgeleiteten Typ einer Variablen (oder parameter) vom Typ Base.
BEISPIEL
Obwohl die obige Zuweisung erlaubt ist, der Wert, der der Variablen zugewiesen pet verliert seine Rasse Feld. Dies nennt man die slicing-problem.
2. SO BEHEBEN SIE DAS SLICING-PROBLEM
Zu besiegen, das problem, wir verwenden Zeiger auf dynamische Variablen.
BEISPIEL
In diesem Fall werden keine Daten der Mitglieder oder member-Funktionen der dynamischen Variablen
wird darauf von ptrD (Nachfahren der Klasse object) verloren. Darüber hinaus, wenn Sie Funktionen verwenden zu können, muss die Funktion sein, die eine virtuelle Funktion.
dog
das ist nicht Bestandteil der KlassePet
(diebreed
Daten-Mitglied) ist nicht kopiert, der in der Variablenpet
? Der code ist nur daran interessiert ist, diePet
Mitglieder-Daten - scheinbar. Slicing ist definitiv ein "problem", wenn es unerwünscht ist, aber ich sehe nicht, dass hier."
((Dog *)ptrP)
" Ich schlage vor, mitstatic_cast<Dog*>(ptrP)
Ich schlage vor, wies darauf hin, dass Sie in der string 'Rasse' schließlich Speicherverlust ohne virtuellen Destruktor (destructor 'string' wird nicht aufgerufen), wenn das löschen durch 'ptrP'... Warum ist das, was Sie zeigen problematisch? Die Lösung ist meist die richtige Klasse design. Das problem in diesem Fall ist, dass nieder zu schreiben Konstruktoren um die Sichtbarkeit zu Steuern beim vererben ist langweilig und schnell vergessen. Sie bekommen nicht überall in der Nähe der Gefahrenzone mit Ihrem code, da es keine Polymorphismus beteiligt ist oder auch nur erwähnt (aufschneiden, schneidet Ihr Objekt aber nicht, dass das Programm abstürzt, hier).
-1 Dies nicht ganz zu erklären ist das eigentliche problem. C++ hat den Wert-Semantik, nicht Referenz-Semantik wie Java, so ist dies alles durchaus zu erwarten. Und der "fix" ist wirklich ein Beispiel von wirklich schrecklich C++ - code. "Fixierung" nicht vorhandene Probleme, wie diese Art des Schneidens durch den Rückgriff auf die dynamische Zuordnung ist ein Rezept für buggy-code, Speicherbelegung und schreckliche Leistung. Beachten Sie, dass es in Fällen, in denen schneiden ist schlecht, aber diese Antwort fehlschlägt, darauf hinzuweisen. Hinweis: der ärger beginnt, wenn Sie ordnen Sie über Referenzen.
Tun Sie auch verstehen, dass der Versuch, Zugriff auf member des Typs, der nicht definiert ist (
Dog::breed
) ist in keiner Weise ein FEHLER mit Bezug zu SCHNEIDEN?InformationsquelleAutor haberdar
Scheint es mir, dass die schneiden nicht so sehr ein problem der anderen, als wenn Sie Ihre eigenen Klassen und Programm sind schlecht konzipiert/entwickelt.
Wenn ich vorbeigehe, ein Unterklasse-Objekt als parameter an eine Methode, die einen parameter vom Typ Oberklasse, ich sollte sicherlich bewusst sein und wissen, die intern aufgerufene Methode arbeitet mit der Oberklasse (aka baseclass) Objekt nur.
Mir scheint es nur die unvernünftige Erwartung, dass die Bereitstellung einer Unterklasse, wo eine baseclass angefordert wird, würde irgendwie das Ergebnis in der Unterklasse, bestimmte Ergebnisse, würde dazu führen, schneiden ein problem zu sein. Die schlechte Gestaltung in der Nutzung der Methode oder eine Arme Unterklasse Umsetzung. Ich vermute, es ist in der Regel das Ergebnis von opfern, gute OOP-design zu Gunsten der Zweckmäßigkeit oder der performance-Gewinne.
geschützt kopieren/Zuweisung auf der Basis der Klasse und das problem ist gelöst.
Du hast Recht. Gute Praxis ist die Verwendung von abstrakten Basisklassen oder zu beschränken, die Zugang zu Kopier - /Abtretung. Jedoch, es ist nicht so leicht zu erkennen, sobald es da ist und einfach zu vergessen, zu kümmern. Aufruf von virtuellen Methoden mit in Scheiben geschnitten *dadurch kann die mysteriösen Dinge passieren, wenn Sie Weg, ohne eine Zugriffsverletzung.
Ich erinnere mich aus meiner C++ - Programmierung Kurse in der Universität, es standen best practices, die wir für jede Klasse erstellt, wir waren erforderlich, um zu schreiben, Standard-Konstruktoren, copy-Konstruktoren und Zuweisungsoperatoren, sowie einen Destruktor. Auf diese Weise haben Sie sichergestellt, dass die Kopie-Konstruktion und dergleichen geschah so, wie Sie es benötigt, ist beim schreiben der Klasse... anstatt später auf ein seltsames Verhalten zeigt.
InformationsquelleAutor Minok
OK, ich werde es versuchen, nach dem Lesen vieler Beiträge erklären, Objekt aufschneiden, aber nicht wie es wird problematisch.
Den Teufelskreis Szenario, das zu einer Speicherbeschädigung führen kann, ist die folgende:
InformationsquelleAutor Dude
Finden Sie ähnliche Antworten hier:http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html
Slicing bedeutet, dass die Daten Hinzugefügt werden, indem eine Unterklasse werden verworfen, wenn ein Objekt der Unterklasse übergeben oder zurückgegeben wird, durch einen Wert oder eine Funktion erwartet ein Objekt Basisklasse.
Erklärung:
Betrachten Sie die folgende Klassendeklaration:
Als baseclass kopieren Sie Funktionen, die nicht wissen, etwas über die abgeleiteten nur der Basis-Teil der abgeleiteten kopiert wird. Dies wird gemeinhin als schneiden.
InformationsquelleAutor Santosh
Ich denke, mehr Erklärung wäre nicht schlecht.
InformationsquelleAutor quidkid
wenn eine abgeleitete Klasse-Objekt zugewiesen ist, auf ein Basis-Objekt-Klasse, die zusätzlichen Attribute der abgeleiteten Klasse ein Objekt werden abgeschnitten (verwerfen) bilden die Basisklasse object.
InformationsquelleAutor Varun_k
Wenn eine Abgeleitete Klasse Objekt zugeordnet ist Basis-Objekt-Klasse, die für alle Mitglieder der abgeleiteten Klasse ein Objekt wird kopiert-Basis-Klasse-Objekt, mit Ausnahme der Mitglieder, die nicht anwesend sind in der base-Klasse. Diese Mitglieder werden in Scheiben Geschnitten Weg durch den compiler.
Dies wird als Objekt Schneiden.
Hier ist ein Beispiel:
Generiert:
InformationsquelleAutor Ghulam Moinul Quadir
Ich rannte über die slicing-problem und prompt hier gelandet. So lassen Sie mich hinzufügen meine zwei Cent auf diese.
Wir haben ein Beispiel aus der "production code" (oder etwas, das kommt irgendwie in der Nähe):
Sagen wir, wir haben etwas, das löst Aktionen. Ein control center UI zum Beispiel.
Das UI braucht, um eine Liste der Dinge, die derzeit in der Lage zu sein, ausgelöst wird. So definieren wir eine Klasse, die enthält die Versand-Informationen. Nennen wir es
Action
. So einAction
hat einige member-Variablen. Für die Einfachheit, die wir gerade haben 2, einstd::string name
und einstd::function<void()> f
. Dann hat Sie einvoid activate()
die gerade führt dief
Mitglied.Also die UI bekommt ein
std::vector<Action>
geliefert. Mir vorstellen, dass einige Funktionen wie z.B.:Nun haben wir festgestellt, wie sieht es aus UI-Perspektive. Kein problem so weit. Aber einige andere Kerl, der arbeitet an diesem Projekt plötzlich entscheidet, dass es spezielle Aktionen, die mehr Informationen benötigen, die
Action
Objekt. Aus welchem Grund auch immer. Das könnte auch gelöst werden, mit lambda, erfasst. Dieses Beispiel ist nicht 1-1 aus dem code.Also der Typ leitet sich von
Action
auf seinen eigenen Geschmack.Er übergibt eine Instanz von seinem home-brewed-Klasse auf den
push_back
dann aber das Programm geht drunter und drüber.Also, was ist passiert?
Als Sie könnte erraten haben: das Objekt wurde in Scheiben geschnitten.
Den zusätzlichen Informationen aus der Instanz verloren wurde, und
f
ist jetzt anfällig für Undefiniertes Verhalten.Ich hoffe dieses Beispiel bringt Licht etwa für jene Leute, die können nicht wirklich vorstellen, wie die Dinge, wenn Sie darüber reden
A
s undB
s abgeleitet wird, in irgendeiner Weise.InformationsquelleAutor Martin B.