2012-11-12 5 views
7

ich folgendes Problem:Kann ich einen anderen copyCtor für konstante und nicht konstante Instanzen schreiben?

Ich habe eine Klasse, die dies tun soll:

Obj o; 
Obj o1(o), o1=o; // deep-copies 
const Obj c(o), c=o; // deep-copies 
const Obj c1(c), c1=c; // shallow-copies 
Obj o2(c), o2=c; // deep-copies 

Wie kann ich das ohne Vererbung vorzugsweise tun? (Ich meine ich tun würde, Const_obj von Obj sonst vererben.)

EDIT:

Mit o.clone() direkt ist keine Option, denn dann könnte ich leicht Fehler einführen versehentlich nicht Klonen.

EDIT:

Schließlich gibt es eine richtige Komplettlösung mit lazy evaluation mit der Idee von Effective C++ von Scott Meyers. Überprüfen Sie meine Antwort unten.

+0

Ich denke, Sie müssen möglicherweise eine clone() -Methode hinzufügen und tun, was Sie explizit wollen. – Caribou

+0

Das ist es, was ich vermeiden möchte, um kaum nachverfolgbar Fehler in meinen Code zu schreiben. So einfach ist es. –

+0

Nun, ich denke, es ist viel gefährlicher - besonders nachdem du Jobs verschoben hast und jemand neues reinkommt ... (My 2 penneth) – Caribou

Antwort

2

nach dem Lesen Effective C++ von Scott Meyers, wird die folgende Lösung:

eine Vorlage definieren, die einen faulen eva tut wertung (mit Referenzzählung):

class Obj : private lazy<Obj_data>{}; 

und lazy speichert die Obj_data privat hat Accessoren geschützt, eine für Modifikation, einer für den Lesezugriff.
Der Modifikator Accessor kopiert die Obj_data bei Bedarf zuerst tief und überträgt dann den Verweis auf die Daten. Der schreibgeschützte Accessor gibt nur eine const-Referenz zurück.

Die Gesamtkosten hierfür sind die Speicherung von 2 zusätzlichen Zeigern (einen für die Daten und einen für den Zähler) und einen Zähler.

Die Umsetzung ist in etwa so:

class lazy{ 
protected: 
    lazy(const lazy&obj){lazy_copy(obj);} 
    //(the required constructors, operator= ...) 

    // accessors: 
    const Obj_data& data() const {return *od;} 
    Obj_data& mod_data() {make_private(); return *od;} 
private: 
    void lazy_copy(const lazy& obj); 
    void make_private(); // this does the actual deep-copy, as late as possible. 
private: 
    counter*; 
    Obj_data* od; 
}; 

So, Lesen und ein Attribut Obj Modifizierung geht

void Obj::method(){ 
    cout << data().some_attribute; // simple read 
    mod_data().i = 10;    // simple modify 
    const Obj_data& const_d = data(); // assignable for lots of read-outs 
    Obj_data& var_d = mod_data();  // assignable for lots of modifications. 
} 

Beachten Sie, dass Sie nur data() in einem const Mitglied als mod_data() ist ein nicht verwenden können, -const Funktion in der Klasse, so ist diese Lösung völlig sicher mit wenig Overhead.

Theorie Hintergrund: das gewünschte Verhalten in der Frage ist ein Implementierungsdetail, betrifft nicht den Client. Deshalb lösen wir es durch private Vererbung.

4

Nein, das geht nicht.

  • Ein Konstruktor kann nicht cv-qualifiziert werden, sodass Sie ihn nicht zwingen können, ein const-Objekt zu erstellen.
  • Der Rückgabetyp einer Funktion (einschließlich Operatoren) ist kein Teil der Signatur, daher können Sie eine Funktion nicht einfach überladen, indem Sie den Rückgabetyp ändern.
  • Auch, wenn es möglich wäre, würde ich es finden wirklich verwirrend. Machen Sie einfach Methoden, die Ihren Bedürfnissen entsprechen, und benennen Sie sie auf eindeutige Weise.

    +0

    Das habe ich mir gedacht. :( –

    +0

    Endlich, fand die richtige Art der Umsetzung. Überprüfen Sie meine Antwort unten. –

    0

    Sie können teilweise mit einem Dummy-Argument:

    class C { 
    public: 
        struct NonStandardCopy { }; 
    
        C (const C &) { 
         // "ordinary" copy constructor with default behavior 
        } 
    
        C (const C &, NonStandardCopy) { 
         // "other" "copy" constructor 
        } 
    }; 
    
    C c = c1; // default 
    C c (c1); // default 
    C c (c1, C::NonStandardCopy()); // non-default 
    

    EDIT: Ein Klon-only Ansatz könnte sein, was Sie wollen (zusammen mit Bewegung Semantik der Performance-Einbußen nicht zu groß sein könnte):

    class C { 
    private: 
        struct DeepCopy { }; 
        struct ShallowCopy { }; 
    
        C (const C &) = delete; 
    
        C (const C &, DeepCopy) { 
         // deep copy 
        } 
    
        C (const C &, ShallowCopy) { 
         // shallow copy 
        } 
    public: 
        // move constructor 
        C (C && other) = default; 
    
        const C clone() const { // 1 
         // shallow copy 
         return C (*this, ShallowCopy()); 
        } 
    
        C cloneToNonConst() const { // 2 
         // deep copy 
         return C (*this, DeepCopy()); 
        } 
    
        C clone() { // 3 
         return cloneToNonConst(); 
        } 
    }; 
    
    C o; 
    C o1 = o.clone(); // call 3 
    const C o2 = o1.clone(); // call 3 
    const C o3 = o2.clone(); // call 1 
    C c4 = o3.cloneToNonConst(); // call 2; o3.clone() will give error 
    
    +0

    +1, guter Gedanke, ich bin jetzt auf der Suche nach machen es automatisch, ich werde wieder hier und schreiben, sobald ich damit fertig bin mit 'Const_obj/Obj'. –

    +0

    Ich bin froh, dass meine Antwort nützlich ist.Ich habe gerade verstanden, dass Sie zwischen dem Konstruieren eines Const und dem Konstruieren eines Nicht-Const unterscheiden wollen.Ich denke, das ist innerhalb eines Konstruktors nicht möglich.Sie können jedoch Public Factory/Clone verwenden Funktionen (const/non-const Rückgabe, const vs. non-const Element Funktionen) und deklarieren die Konstruktoren als private – JohnB

    +0

    Sorry, aber es kompiliert noch nicht für mich, wenn ich die Tests in eine Hauptfunktion setzen, da der copyCtor privat ist –

    Verwandte Themen