Frage

Ich habe eine Klasse, die so genannt vir erstellt, mit einer Funktion bewegen:

class vir
{
public:
     vir(int a,int b,char s){x=a;y=b;sym=s;}
     void move(){}
};

(Es ist von einer Klasse abgeleitet mit Variablen int x, int y, und char sym) Ich habe eine Klasse von dieser, genannt subvir abgeleitet:

class subvir:public vir
{
public:
     subvir(int a,int b,char s){x=a;y=b;sym=s;}
     void move();
};
subvir::move()
{
     x++;
     return;
}

Und dann habe ich eine Reihe von vir, und legte eine subvir hinein

subvir sv1(0,0,'Q');
vir vir_RA[1]={sv1};

Aber wenn ich versuche sv1.move () zu verwenden:

vir_RA [0] .move ();

Es nutzt die vir Bewegung ({}), anstatt die subvir Bewegung ({x} ++). Ich habe versucht, eine vir und vir_RA machen sv1 ein vir, und es funktioniert, und es funktioniert auch, wenn ich sie beide subvir machen, aber ich brauche sie, anders zu sein. Ich habe versucht, vir :: move () eine rein virtuelle machen, aber dann bekomme ich einen Fehler untermauern das Array. Wer weiß, wie ich move () bekommen zu arbeiten, wenn ich es aus dem Array verwenden?

War es hilfreich?

Lösung

Sie benötigen ein Array von Zeigern in diesem Fall eher als eine Reihe von Instanzen. Verwenden Sie vir * [] anstelle von vir []

Andere Tipps

Sie führen zu einem Problem genannt Slicing . Verwenden Sie ein Array von Zeigern, oder so etwas wie Boost.ptr_container .

Die Basisklasse muss virtual Funktionen müssen Sie bekommen, was Sie wollen, diese reine Herstellung wird in einer abstrakten Basisklasse zur Folge haben - etwas, das man nicht instanziieren. Sie können jedoch nach wie vor Zeiger / Referenzen auf abstrakte Basisklassen erstellen und abgeleitete Klasse Objekte zuweisen. Ihre Basisklasse ist am besten wie folgt dargestellt:

class vir
{
public:
     vir(int a,int b,char s){x=a;y=b;sym=s;}
     virtual void move(){}
};

Das macht die move der abgeleiteten Klasse als auch virtuell. Jedoch Ihre move Definition fehlt ein Rückgabewert und wird nicht kompiliert. Versuchen Sie:

void subvir::move()
{
     x++;
     return;
}

Beachten Sie, dass Sie entweder Zeiger benötigen oder Verweise auf abgeleitete Klassen für dynamische Bindung zu arbeiten (wie in den anderen Antworten erwähnt). Anstatt also eine Reihe von vir Objekten, eine Reihe von Basisklasse Zeigern verwenden:

vir* v[ 2 ] = { new subvir(0, 0, 'Q'), new subvir(10, -10, 'P') };

Sie sollten auch f lesen, Sie auf den folgenden Abschnitten des C ++ FAQ Lite:

Zwei Dinge. Das Array ist ein Array von vir ist so natürlich ist es die vir :: Bewegung verwendet. bewegen () ist keine virtuelle Methode.

Aber wichtiger schneidet. Sie können nicht Subklassen in ein Array stellen. Wenn sizeof vir! = Sizeof subvir, wird das Array nicht korrekt ausgerichtet sind. Derzeit sind sie die gleiche Größe. Aber was passiert, wenn sie nicht sind.

Ja, im Grunde Compiler erlaubt keine Subklassen in Arrays, weil Arrays sind fest für die Schriftgröße initialisiert und Subtypen neigen größer sein als die Eltern und es würde zu Problemen führen, wenn Sie könnten initialisieren Arrays mit Werten Subtyps. Was passiert, ist wirklich Compiler weist erste Array N * Größe (base_type) Bytes. Und dann kopiert Größe (base_type) Bytes von jedem der Initialisierung Objekte. wenn sie von verschiedenen Typen, würden sie abgeschnitten werden, und seltsame Dinge in Ihrem Code passieren könnten.

Lassen Sie mich die bisherigen Antworten konsolidieren.

Es gibt eigentlich zwei Fragen hier. Eine davon ist Slicing. Sie sind eine Reihe von virs mit einer Kopie eines subvir initialisiert. aus dem subvir und kopiert sie in das Array In solchen Fällen schneidet der Compiler den vir Teil, so dass Sie wirklich bekommen es nur vir Objekte. Jetzt in Ihrem speziellen Fall hat subvir keine zusätzlichen Datenelemente über die von vir, so Slicing ist etwas degeneriert und das vir Objekt sieht viel wie ein subvir ein. Jedoch vir und subvir sind verschiedene Klassen und das Objekt in dem Array endet als ein vir-Objekt und keine subvir Objekt als vir verkleidet. Eine Möglichkeit, die Differenz zwischen den beiden praktisch manifestieren würde, auch wenn beide die gleichen Datenelemente hatten, ist, wenn vir virtuelle Funktionen hatte durch subvir überlastet. In diesem Fall wird die vtable Zeiger in dem Objekt in dem Array zu Virs vtable weisen darauf, nicht subvir ist. Natürlich wäre es noch deutlicher, wenn subvir zusätzliche Datenelemente nicht in vir gefunden enthalten sind.

Das zweite Problem ist Polymorphismus. Am Punkt der Nutzung (der Anruf zu bewegen ()) der Compiler denkt, dass Sie den Aufruf die Methode move () ein Objekt vom Typ vir (da das Array ein Array von virs ist). (Der Compiler ist natürlich richtig, um das Aufschneiden so durch das Denken, degeneriert, wie es in diesem Fall sein kann.) Wäre es tatsächlich ein subvir Objekt gewesen, wie Sie intented, könnten Sie subvir :: move (), indem sie Bewegung genannt bekommen ( ) virtuell in vir.

Um das gewünschte Verhalten erhalten Sie ein Array von Zeigern verwenden könnten (aber dann würden Sie direkt auf sv1, nicht eine Kopie davon betrieben wird, es sei denn, Sie zuerst eine Kopie und initialisiert das Array mit einem Zeiger auf die Kopie erstellt).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top