2012-12-13 12 views
6

Używam zmiennej członka i w pewnym momencie programu chcę ją zmienić, ale wolę ją "zablokować" wszędzie indziej, aby zapobiec niezamierzonym zmianom.Czy zmienna może być zablokowana, aby zapobiec zmianom w C++?

Kod wyjaśnić:

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 
}; 

Pytanie brzmi: Czy to może być osiągnięte w jakiś sposób? Coś jak stały const_cast?

Wiem, że mógłbym użyć listy inicjalizacyjnej konstruktora i stałej od razu, ale muszę zmienić moją zmienną później.

+2

zrobić to prywatne i zmienić tylko wtedy, gdy chcesz? – Chad

+0

Chcesz, aby implementacja nie zmieniła x, lub chcesz uniemożliwić komukolwiek wywoływanie metody? – Joe

+0

@Joe: Chcę rzucić błąd podczas kompilacji. – Petr

Odpowiedz

2

Dobra, wszystkie inne odpowiedzi, których nie lubię, więc oto mój pomysł: ukryj zmienną.

#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++; 
    } 
}; 

nadal istnieją sposoby na ominięcie blokady zmiennej (takie jak this->x), ale nic nie można zrobić dla tych sytuacjach.

+0

Wygląda na to, że jeśli masz zamiar to zrobić, potrzebujesz czegoś takiego jak '#define lock (v) const auto & v = this-> v', więc w funkcji wyświetla się jako' lock (x);/* ... */'. Szablon może pozwolić ci zrobić to samo czysto. –

+0

To jest eleganckie rozwiązanie, jeśli chcę zapobiec edycji tylko w jednej funkcji, ale czy mogę temu zapobiec? – Petr

+1

@Petr: Nie ma sposobu, aby to uogólnić nawet w teorii. W pytaniu znalazłeś komentarze, aby powiedzieć _us_, które zmienne są zablokowane w jakich funkcjach. Kompilator będzie potrzebował tego samego ogólnego rodzaju informacji.Łatwo jest uczynić go nie edytowalnym w funkcji _any_, ale jeśli jest on edytowalny w niektórych, musisz powiedzieć nam/kompilatorowi, który funkcjonuje. –

0

Cóż, nie możesz zrobić tego, co próbujesz zrobić ... Ktoś mnie poprawi, jeśli się mylę.

+1

Chce, aby 'foo1' zmienił x, ale nie' foo2' – Chad

+0

@benjarobin: zmienne można zablokować ukrywając je –

+0

@Mooing Duck: Ale jeśli to ukryję (cokolwiek to znaczy), czy mogę użyć go tylko do odczytu cel gdzie indziej? – 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 
}; 

Jeśli zaznaczysz funkcji składowej const tak, że nie może nic w tym państwie, które modyfikowania element obiektu (chyba, że ​​członek jest mutable lub static zrobić - i nie jest naprawdę static członek obiektu w ogóle).

Należy zauważyć, że to nie tylko uniemożliwi wywołanie funkcji, która próbuje wykonać taką modyfikację - raczej funkcja oznaczona jako const, ale próbuje zmodyfikować stan obiektu, który nie zostanie skompilowany w ogóle.

Należy jednak dodać, że wcale nie jestem przekonany, że to naprawdę najlepszy projekt. Przeciwnie, dla mnie brzmi to tak, jak twoje wymagania na x i y są wystarczająco skomplikowane, że prawdopodobnie miałyby więcej sensu jako oddzielne klasy, które wymuszają odpowiednie ograniczenia bezpośrednio (np. Przez zapewnienie przeciążenia dla operator=, które akceptuje tylko dane wejściowe pod okoliczności).

Innymi słowy, wykorzystanie mutable mam pokazane powyżej jest (chyba) to najprostszy i najbardziej bezpośredni odpowiedź na pytanie już poproszony, ale wydaje się dość prawdopodobne, że nie jesteś naprawdę pytaniem pytanie, które powinieneś, i bardziej prawdopodobne jest, że skorzystasz na zmianie projektu - niestety, nie powiedziałeś nam wystarczająco dużo o "wielkim obrazie", aby zasugerować, jaki może być lepszy projekt.

+0

@MooingDuck: Dzięki. Zaktualizowano. –

+0

'zmienne'? Myślę, że porzuciłbym koncepcję "const" i osobiście ukryłam zmienną. Albo testy jednostkowe czy coś. –

+1

@MooingDuck: To najbardziej bezpośrednia odpowiedź na to, o co prosi. Przypuszczam jednak, że powinienem dodać trochę ostrzeżenia. –

1

Cóż, nie jestem pewien, że jest warta wysiłku, tak, na wszelki wypadek to quiz, albo czegoś, spróbuj połączyć prywatny dziedziczenie z przyjacielem:

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

Nie test, ale po prostu moja ciekawość. – Petr

+0

@Petr - Nie wypróbowałem mojego rozwiązania, daj mi znać, jeśli jest coś do naprawienia. Zgodnie z moją najlepszą wiedzą powinien spełniać twoje ograniczenia. – PiotrNycz

+0

@Petr (+1) dla ciekawości, zawsze uważam, że to dobrze. – PiotrNycz

0

Technicznie rzecz biorąc, odpowiedź brzmi nie, jak długo klasa może zobaczyć zmienną i nie jest stała - może ją modyfikować. Ale możesz osiągnąć to, co chcesz, oddzielając zmienną, którą chcesz zablokować w oddzielnej klasie.

0

Utwórz klasę z prywatną zmienną x. W nim napisz swoją metodę.

Pochodzi z tej klasy rzeczywista klasa. Spraw, aby właściciel x był przyjacielem aktualnej klasy.

Uchwyt X używa CRTP jak odlewanie (odlewanie statyczne do podstawy) w uchwycie x, aby uczynić z niego wskaźnik do aktualnej klasy.

Ujawnij x getter z posiadacza x.

Nie zawracałbym sobie głowy, ale to jest lepsze niż nadużywanie mutable i const.

1

Bądź xprivate członkiem subClass, i uczynić foo1 funkcją przyjacielem subClass. W ten sposób:

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 ; 
}; 

Powoduje to błąd kompilatora, dokładnie tam, gdzie go chciał.

+0

Wprawiłem w zakłopotanie, ponieważ nigdy nie używasz 'read_x', ale masz rację: http://ideone.com/JTkfSq –

+0

@Mooing Duck: Jakie użycie jest zmienną tylko do zapisu? – TonyK

Powiązane problemy