Подтвердить что ты не робот

Имя для публичного атрибута const и private writeable?

Программирование на С++, я часто хочу предоставить пользователю доступ к атрибуту класса только для чтения, а сам класс - для чтения и записи. Я ненавижу методы XxxGet(), поэтому часто использую public const & для частного атрибута, например:

class counter {
  private:
     int _count;

  public:
     const int & count;

     counter : _count( 0 ), count( _count ){}

     void inc( void ){ _counter++; }
};

Есть ли общее название для этого трюка?

4b9b3361

Ответ 1

Мое личное имя для этого трюка - плохая идея.

Я бы избегал подхода, который вы следуете, поскольку он несет дополнительную ненужную стоимость. Если вы добавите аксессоров, они могут быть привязаны по мере необходимости, с единственным штрафом в том, что нужно ввести дополнительную пару круглых скобок:

class counter {
    int _count;
public:
    counter() : _count() {}
    int count() const { return _count; }
    void inc() { ++_count; }
};

Основное различие заключается в том, что в вашем решении вы увеличиваете размер объекта по одной ссылке (для большинства реализаций это означает указатель), а затем для каждого доступа требуется дополнительная косвенность. С другой стороны, с помощью аксессора действительная переменная используется, функция будет оптимизирована (встраивается и разрешается одно чтение переменной).

Как и для собственного имени для такого типа конструкции, я никогда не видел вашу конкретную конструкцию на С++, но если вы рассматриваете другие языки, это основная концепция свойства в С#, где вы можете сделать getter public и setter private.

РЕДАКТИРОВАТЬ. Я думаю, что эта плохая идея может быть неверно истолкована как личное мнение (которое она есть), но рассмотрим побочные эффекты этого проекта:

Из-за ссылки в объекте вы запрещаете неявное определение оператора присваивания. Гораздо хуже, конструктор копирования будет компилироваться, но не работает, как ожидалось:

// consider the implementation with the const reference
counter c1;
counter c2( c1 );          // compiles, so it must work
c2.inc();
std::cout << c2.count;   // outputs 0
// c2 = c1;              // error: well, at least this does not compile!

Проблема заключается в том, что созданный компилятором конструктор копирования сделает ссылку count в c2 ссылкой на тот же int, на который ссылается ссылка count в c1, что может привести к жесткому -введите тонкие проблемы в свой код, которые на самом деле довольно сложно отлаживать.

Ответ 2

Edit

Сейчас Я думал о названии, которое можно было бы считать одним и тем же шаблоном. Хотя обычно не используется для переменных-членов.

На самом деле это может быть имя, которое было популярно в библиотеке Boost Tuple, а также в реализациях TR1/С++ 11:

Tieing

Типичный пример:

 tuple<int> tie(ref(some_var));
 // or shorter:
 auto tied = tie(var1, var2, var3);

Условные осложнения

Самое близкое имя для этого шаблона (anti?), о котором я мог бы сразу подумать, это: указатель или сглаживание ссылок. Это не очень хорошая идея по многим причинам, некоторые из которых были упомянуты

  • макет класса + размер
  • семантика копирования/назначения
  • Оптимизация компилятора: компилятор избегает делать предположения о значении (регистровых) переменных, когда он знает, что ссылки могут указывать на одно и то же место в памяти.

В дополнение к точкам, которые делает Дэвид, компилятор не сможет создать по умолчанию

  • семантически допустимый конструктор копирования
  • оператор присваивания Оператор присваивания

для вашего класса, который содержит ссылки. Также обратите внимание, что ваш класс больше не может быть POD

Ответ 3

Ряд других уже осудил эту идею, и я (в основном), как правило, согласен с ними. Хотя немало людей, вероятно, не любят его (по крайней мере), если я собираюсь что-то поддержать в этом порядке, я бы сделал что-то вроде этого:

class counter { 
    int count_;
public:
    counter(int init=0) : count_(init) {}
    operator int() const { return count_; }
    void inc() { ++count_; }
};

Единственная проблема с этим - это то, что делится с неявными преобразованиями в целом: что неявное преобразование может произойти, даже если вы этого не хотите. OTOH, тот факт, что это преобразование, предоставляемое пользователем, фактически устраняет многие проблемы - только одно неявное преобразование произойдет автоматически в любой заданной ситуации, поэтому (например) тот факт, что вы поставили преобразование в int, будет не означает, что a counter со значением 0 может быть неявно преобразован из a counter в int в (null) pointer to T, потому что это будет связано с двумя неявными преобразованиями.

Иногда это может вызвать проблему в любом случае, и в этом случае (с С++ 11) вы можете сделать оператор преобразования explicit, так что это произойдет только тогда, когда/если пользователь выполняет явное преобразование, например

counter t;

int x = t;  // allowed by code above, but not with `explicit` conversion operator.

int y = static_cast<int>(t);    // allowed with `explicit` conversion operator.