2012-12-13 3 views
6

Ich benutze eine Member-Variable und an einem Punkt des Programms möchte ich es ändern, aber ich bevorzuge es "überall zu sperren", um unbeabsichtigte Änderungen zu verhindern.Kann eine Variable gesperrt werden, um Änderungen in C++ zu verhindern?

-Code zu erklären:

class myClass { 
    int x; // This should be prevented to being changed most of the time 
    int y; // Regular variable 
    myclass() {x = 1;} 
    void foo1() {x++; y++;} // This can change x 
    void foo2() {x--; y--;} // This shouldn't be able to change x 
          // I want it to throw a compile error 
}; 

Die Frage ist: Kann es in irgendeiner Weise erreicht werden? Etwas wie permanente const_cast?

Ich weiß, ich könnte Konstruktor Initialisierungsliste und Konstante sofort verwenden, aber ich muss später meine Variable ändern.

+2

machen Sie es privat, und ändern Sie es nur, wenn Sie möchten? – Chad

+0

Sie möchten verhindern, dass die Implementierung x ändert, oder möchten Sie verhindern, dass jemand die Methode aufruft? – Joe

+0

@Joe: Ich möchte es beim Kompilieren einen Fehler werfen. – Petr

Antwort

2

Okay, all die anderen Antworten, die ich nicht mag, also hier ist meine Idee: Verstecke die Variable.

#define READONLY(TYPE, VAR) const TYPE& VAR = this->VAR //C++03 
#define READONLY(VARIABLE) const auto& VARIABLE = this->VARIABLE //C++11 

class myClass { 
    int x; // This should be prevented to being changed most of the time 
    int y; // Regular variable 
    myClass() :x(1), y(2) {} 
    void foo1() {// This can change x 
     x++; 
     y++; 
    } 
    void foo2() {// This shouldn't be able to change x 
     READONLY(x); //in this function, x is read-only 
     x++; //error: increment of read-only variable 'x' 
     y++; 
    } 
}; 

Es gibt immer noch Möglichkeiten, um die Verriegelung der Variablen (wie this->x) zu umgehen, aber nichts kann für solche Situationen durchgeführt werden.

+0

Scheint mir, wenn du das machst, willst du etwas wie '#define lock (v) const auto & v = this-> v', also in der Funktion erscheint es als' lock (x);/* ... */'. Mit einer Vorlage können Sie das selbe sauberer machen. –

+0

Das ist eine elegante Lösung, wenn ich die Bearbeitung in nur einer Funktion verhindern möchte, aber kann ich sie generell verhindern? – Petr

+1

@Petr: Es gibt keine Möglichkeit, das auch in der Theorie zu verallgemeinern. In der Frage hatten Sie Kommentare um uns mitzuteilen, welche Variablen in welchen Funktionen gesperrt sind. Der Compiler wird dieselbe allgemeine Art von Information benötigen.Es ist einfach, es in _any_-Funktion nicht editierbar zu machen, aber wenn es in einigen editierbar ist, müssen Sie uns/den Compiler, der funktioniert, sagen. –

0

Nun, Sie können nicht tun, was Sie versuchen zu tun ... Jemand korrigiert mich, wenn ich falsch liege.

+1

Er will 'foo1' ändern x, aber nicht' foo2' – Chad

+0

@benjarobin: die Variablen können gesperrt werden, indem sie versteckt –

+0

@Mooing Duck: Aber wenn ich es verstecken (was auch immer das bedeutet), könnte ich es nur zum Lesen verwenden Zweck woanders? – Petr

1
class myClass { 
    int x; 
    mutable int y; 
public: 
    myclass() : x(1) {} 
    void foo1() {x++; y++}  // this can change x or y 
    void foo2() const { y--; } // this can't change x by can change y 
}; 

Wenn Sie eine Memberfunktion const wie diese markieren, können Sie nichts in diesem Element tun, die ein Mitglied des Objekts ändern würde (es sei denn, dass die Mitglieds mutable oder static ist - und static ist nicht wirklich ein Mitglied eines Objekts überhaupt).

Beachten Sie, dass dies Sie nicht einfach daran hindert, eine Funktion aufzurufen, die versucht, eine solche Änderung durchzuführen - eine Funktion, die mit const markiert ist, aber versucht, den Objektstatus zu ändern, wird überhaupt nicht kompiliert.

Ich sollte jedoch hinzufügen, dass ich überhaupt nicht davon überzeugt bin, dass dies wirklich das beste Design ist. Eher im Gegenteil, es klingt für mich so, als ob Ihre Anforderungen an x und y ausreichend komplex sind, dass sie wahrscheinlich sinnvoller wären als separate Klassen, die die richtigen Einschränkungen direkt erzwingen (z. B. durch Bereitstellung einer Überlast für operator=, die nur Eingaben unter dem richtigen akzeptiert Umstände).

Mit anderen Worten, die Verwendung von mutable ich oben gezeigt habe, ist (glaube ich) die einfachste und direkteste Antwort auf die Frage, die Sie gefragt haben, aber scheint es ziemlich wahrscheinlich, dass Sie nicht wirklich sind gefragt die Frage, die Sie sollten, und Sie werden wahrscheinlich von der Änderung des Designs profitieren - leider haben Sie uns nicht genug über das "große Bild" gesagt, um vorzuschlagen, was das bessere Design sein könnte.

+0

@MooingDuck: Danke. Aktualisiert. –

+0

'veränderbar'? Ich denke, ich hätte die "const" Idee fallen gelassen und die Variable persönlich versteckt. Oder Unit Tests oder so etwas. –

+1

@MooingDuck: Es ist die direkteste Antwort auf das, was er fragt. Ich denke, ich sollte ein wenig Warnung hinzufügen. –

1

Nun, ich bin nicht sicher, ob es mir lohnt, Ihre Bemühungen, wie auch immer, nur für den Fall des Quiz oder etw ist, versuchen private Vererbung mit Freund zu kombinieren:

class MyClassX { 
protected: 
    MyClassX() : x(1) {} 
    int x; 
public: 
    int getX() const { return x; } // read only access 
}; 
class MyClassY { 
protected: 
    MyClassY() : y(0) {} 
    int y; 
    friend class MyClass; 
public: 
    int getY() const { return y; } 
}; 
class MyClassXY : private MyClassX, private MyClassY { 
public: 
    void foo1() {x++; y++}  // this can change x or y 
}; 
MyClass : public MyClassXY { 
public: 
    void foo2() const { y--; } // this can't change x but can change y 
}; 
+0

Kein Test, sondern einfach meine Neugier. – Petr

+0

@Petr - Ich habe meine Lösung nicht versucht, lassen Sie mich wissen, ob es etwas zu beheben ist. Nach meinem besten Wissen sollte es Ihre Einschränkungen erfüllen. – PiotrNycz

+0

@Petr (+1) für Neugier, ich glaube immer, das ist eine gute Sache. – PiotrNycz

0

Technisch gesehen ist die Antwort nein, wie lang kann die Klasse die Variable sehen und sie ist nicht konstant - sie kann sie verändern. Aber Sie könnten erreichen, was Sie wollen, indem Sie die Variable, die Sie sperren möchten, in eine separate Klasse entkoppeln.

0

Erstellen Sie eine Klasse mit einer privaten x-Variablen. Schreibe darin deine Methode.

Ableiten von dieser Klasse Ihre tatsächliche Klasse. Machen Sie den x-Halter zu einem Freund der aktuellen Klasse.

X Halter verwendet CRTP wie Casting (statisch zu Base) in den X Halter, um dies zu einem Zeiger auf Ihre tatsächliche Klasse zu machen.

Setzen Sie einen x-Getter von Ihrem x-Halter frei.

Ich würde mich nicht stören, aber das ist besser als missbrauchen veränderlich und const.

1

Make x ein private Mitglied einer subClass und machen foo1 ein Freund Funktion des subClass. Gefällt mir:

class myClass { 
    int y; // Regular variable 
    myClass() : x (1) {} 
    void foo1() {x.x++; y++;} // This can change x 
    void foo2() {x.x--; y--;} // This shouldn't be able to change x 
          // I want it to throw a compile error 
    class subClass { 
     friend void myClass::foo1() ; // This must come after the declaration of foo1 
     int x ; // private 
    public: 
     subClass (int x) : x (x) { } 
     int read_x() const { return x ; } 
     } x ; 
}; 

Dies wirft einen Compilerfehler, genau dort, wo Sie es wollten.

+0

Ich war verwirrt, da Sie nie 'read_x' verwenden, aber Sie haben Recht: http://ideone.com/JTkfSq –

+0

@Mooing Duck: Was nutzt eine schreibgeschützte Variable? – TonyK

Verwandte Themen