C ++ Virtual Constructor, ohne Klon ()

8

Ich möchte "tiefe Kopien" eines STL-Containers von Zeigern zu polymorphen Klassen durchführen.

Ich kenne das Entwurfsmuster Prototyp , das mit Hilfe der virtuellen Ctor Idiom implementiert wurde, wie im C ++ FAQ Lite, Artikel 20.8 .
Es ist einfach und unkompliziert:

%Vor%

Eine tiefe Kopie ist dann:

%Vor%

Nachteile

Wie Andrei Alexandrescu erklärt es :

  

Die clone() Implementierung muss in allen abgeleiteten Klassen dem gleichen Muster folgen; Trotz seiner sich wiederholenden Struktur gibt es keinen vernünftigen Weg, um die Funktion clone() member (über Makros hinaus) zu definieren.

Außerdem können Kunden von ABC möglicherweise etwas Schlechtes tun. (Ich meine, nichts hindert Kunden daran, etwas Schlechtes zu tun, also wird es passieren.)

Besseres Design?

Meine Frage ist: Gibt es eine andere Möglichkeit, eine abstrakte Basisklasse klonbar zu machen, ohne dass abgeleitete Klassen klonbezogenen Code schreiben müssen? (Helferklasse? Vorlagen?)

Das ist mein Kontext. Hoffentlich hilft es mir, meine Frage zu verstehen.

Ich entwerfe eine Klassenhierarchie, um Operationen für eine Klasse Image durchzuführen:

%Vor%

Bildoperationen sind benutzerdefiniert: Clients der Klassenhierarchie implementieren ihre eigenen Klassen, die von ImgOp abgeleitet sind:

%Vor%

Mehrere Operationen können sequentiell für ein Bild ausgeführt werden:

%Vor%

Wenn mehrere Bilder vorhanden sind, kann das Set aufgeteilt und über mehrere Threads geteilt werden. Um "Thread-Sicherheit" zu gewährleisten, muss jeder Thread seine eigene Kopie aller Operationsobjekte enthalten in v - v wird zu einem Prototyp, der in jedem Thread tief kopiert wird.

>

Bearbeitet: Die threadsichere Version verwendet das Entwurfsmuster "Prototyp", um die Kopie von spitz zu Objekten - nicht von ptrs:

zu erzwingen %Vor%

Dies ist sinnvoll, wenn Bildverarbeitungsklassen klein sind: Serialisieren Sie Zugriffe auf eindeutige Instanzen von ImgOp s nicht, sondern stellen Sie jedem Thread eigene Kopien zur Verfügung.

Der schwierige Teil besteht darin, Autoren von neuen ImgOp -abgeleiteten Klassen zu meiden, um klonbezogenen Code zu schreiben. (Weil das Implementierungsdetail ist - deshalb habe ich Pauls Antworten mit dem seltsam wiederkehrenden Muster abgetan.)

    
Julien-L 04.05.2010, 14:04
quelle

3 Antworten

2

FYI, das ist der Entwurf, mit dem ich herauskam. Danke Paul und FredOverflow für deine Eingaben. (Und Martin York für Ihren Kommentar.)

Schritt # 1, Kompilierzeit-Polymorphismus mit Vorlagen

Polymorphismus wird zur Kompilierungszeit unter Verwendung von Vorlagen und impliziten Schnittstellen :

durchgeführt %Vor%

Jetzt liegt der gesamte klonbezogene Code in einer eindeutigen Klasse. Es ist jedoch jetzt unmöglich, einen Container mit ImgOp s für verschiedene Operationen zu templatisieren:

%Vor%

Schritt # 2, Fügen Sie eine Abstraktionsebene hinzu

Fügen Sie eine Nicht-Template-Basis hinzu, die als Schnittstelle fungiert:

%Vor%

Jetzt können wir schreiben:

%Vor%

Aber es wird schwierig, Bildoperationsobjekte zu manipulieren:

%Vor%

Schritt # 3, Fügen Sie eine "cloning pointer" -Klasse

hinzu

Erstellen Sie basierend auf der Lösung von FredOverflow einen Klonzeiger, um die Verwendung des Frameworks zu vereinfachen.
Dieser Zeiger muss jedoch nicht templatisiert werden, da er nur einen Typ von ptr enthält - nur der ctor muss templatisiert werden:

%Vor%

Jetzt können wir schreiben:

%Vor%     
Julien-L 10.05.2010, 08:51
quelle
7

Sie können das merkwürdig rekursive Muster verwenden, aber es könnte Ihren Code weniger lesbar machen. Sie werden weiterhin Kopierkonstruktoren benötigen. Es funktioniert wie folgt.

%Vor%     
fulmicoton 04.05.2010 14:17
quelle
1
  

Eine tiefe Kopie ist dann: [for loop]

Sie lassen den Client den Vektor explizit klonen. Ich bin nicht sicher, ob das Ihre Frage beantwortet, aber ich würde einen Vektor von intelligenten Zeigern vorschlagen, so dass das Klonen automatisch geschieht.

%Vor%

Natürlich möchten Sie nicht, dass diese impliziten Kopien passieren, wenn Sie einen Vektor oder etwas in der Größe verändern, also müssen Sie in der Lage sein, Kopien von Bewegungen zu unterscheiden. Hier ist meine C ++ 0x-Spielzeug-Implementierung von cloning_pointer , die Sie möglicherweise an Ihre Bedürfnisse anpassen müssen.

%Vor%

Julien: && ist kein "ref von ref", es ist eine rvalue-Referenz, die nur an modifizierbare rvalues ​​bindet. Sehen Sie dieses ausgezeichnete (aber leider etwas veraltete) Tutorial und video für einen Überblick über Rvalue-Referenzen und wie sie funktionieren.

    
fredoverflow 04.05.2010 16:25
quelle

Tags und Links