Принудительное использование Getter / Setter в одном классе (C++)

Есть ли способ в C++ для обеспечения использования методов получения или установки в пределах класса?

class C{
   private:
   int x;        // should only be Changed by setX();

   private:
   setX(int i){
       (...)     // enforce some complicated invariantes
       x = i;
   };

   m(){
      x = 5;     // should not not allowed
   }
}

Единственное, что приходит мне в голову, - это поместить все суперприватные члены как частные переменные в абстрактный базовый класс с защищенными геттерами / сеттерами.

Но это не похоже на хорошую практику.

Существуют ли более распространенные способы или соглашения, гарантирующие, что каждый использует сеттеры?

(Моя цель: если класс становится больше, мне трудно вспомнить, какие переменные содержат инварианты с ними. И в настоящее время, прежде чем задавать какую-либо переменную, я ищу, создал ли я геттер или сеттер (чтобы выяснить, должен ли я учитывать инварианты). Но я хочу избавиться от этого непрофессионального поиска каждый раз.)

4 ответа

Решение

Вы можете воспользоваться композицией следующим образом:

class C_int
{
public:
    void setX(int i)
    {
        /* enforce invariants */
        x = i;
    }

private:
    int x;
};

class C
{
pulbic:
    void m()
    {
        x.setX(5);
        // x.x = 5; // Won't compile.
    }

private:
    C_int x;
};

Но я нахожу странным, что это актуальная проблема для вас, ИМХО. Вы писатель C класс и его члены. Вы контролируете, как x переменная для чтения / записи, и x не является частью открытого интерфейса класса. Хотя верно, что другие люди (например, сопровождающие) могут писать код, который нарушает инварианты в будущем, модульные тесты должны быть в состоянии охватить эти случаи.

А) отдавать предпочтение методам доступа по всей вашей кодовой базе для согласованности. тогда вам будет легче заметить прямой доступ к участникам. если вам нужны специальные методы доступа, создайте специальные методы:

void setFoo(const t_foo& foo) {
    assert(foo.isValid());
    this->d_foo = foo;
}

void invalidateFoo() {
    this->d_foo = t_foo::InvalidFoo();
}

б) чтобы получить ответ: я часто создаю внутренний класс (временно в некоторых случаях):

class C {
    class t_inner {
    public:
    /* ... */
        void setX(int arg) {
            /* enforce some complicated invariants... */
            this->x = arg;
        }
        const int& getX() const {
            /* ... */
            return this->x;
        }
    private:
        int x;
    };
public:
/* ... */
private:
/* ... */
    void m() {
        this->inner().setX(5);
    }
private:
    t_inner d_inner;
};

В Visual C++ __declspec( property ) может быть использован для этой функции:

__declspec(property(put=setFunction, get=getFunction)) data-type property-name; 

Смотрите эту статью

Чистый ответ - нет. Для этого нет языковой функции; Вы можете сделать некоторые изменения, чтобы достичь этого, но это загромождает ваш код.

Другие вопросы по тегам