Является ли разумной практикой обеспечение неизменности всех экземпляров с использованием константных публичных членов?

У меня есть класс — который в основном представляет собой структуру группы полей (скажем, что-то вроде двумерной точки; но это просто синтетический пример для целей этого вопроса) — из которых я хочу только неизменные экземпляры. Очевидно, я могу сделать члены данных приватными и иметь только методы получения:

class Point2d {
protected:
double x;
double y;

public:
Point2d(double _x, double _y) : x(_x), y(_y) {}
double getX() const { return x; }
double getY() const { return y; }
double norm() const { return x*x + y*y; }
}

Но я подумал, может быть, лучше сделать это:

class Point2d {
public:
const double x;
const double y;

public:
Point2d(double _x, double _y) : x(_x), y(_y) {}
double norm() const { return x*x + y*y; }
Point2d operator=(const Point2d& p) = delete;
}

Редактировать: Третий вариант — обеспечить неизменность, используя только constв объявлении отдельных переменных, причем сам класс является изменяемым, т.е.

class Point2d {
public:
double x;
double y;

public:
Point2d(double _x, double _y) : x(_x), y(_y) {}
double norm() const { return x*x + y*y; }
}

// ...

Point2d magicalTransformation(const Point2d& p1, const Point2d& p2);

Что является более разумным способом обеспечения неизменности?

2

Решение

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

Конечно, любой пользователь, который хочет замерзать экземпляр может сделать это с помощью const, Таким образом, вы не предоставляете пользователю никаких «новых» функций, но лишаете их гибкости: стоит ли это того?

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

Таким образом, я бы посоветовал вам просто предотвратить любые изменения Кроме от назначения. Этого достаточно, чтобы легко поддерживать классовые инварианты.

2

Другие решения

Это считается разумным?

Да. На мой взгляд, это лучший стиль, так как он улучшает читабельность.
Я бы когда-нибудь предпочел const (неизменный) public член над подходом геттера. Фактически, каждый тип данных отправляет определенное сообщение, если оно объявлено надлежащим образом. Например:

  • const data ==> Член не будет изменен в своем
    продолжительность жизни
  • public ==> Член читается вне class
  • protected member ==> Член читается в наследстве
    иерархия
  • private member ==> Член читается в class только область

Так что здесь цель ясна. Вы объявляете пользователя const как только вы уверены, что это не изменится в течение всей жизни. Спецификатор доступа должен выбираться в зависимости от того, где будут использоваться потенциальные методы получения.

Кроме того, мне действительно нужен модификатор const в методе norm с
const public Члены?

Да. Это предпочтительнее, потому что вам нужно const правильная версия для const объекты или внутри другого const методы.

редактировать:
По поводу измененного вопроса. После того, как у вас есть один const член внутри class, operator = неявно удаляется, поэтому вам не нужно = delete Это. Это просто вопрос вкуса. Для меня это становится излишним.
На самом деле в g ++ компиляторе, если вы попытаетесь изменить такой объект с помощью присваивания, компилятор сам сгенерирует ошибку, такую ​​как:

error: use of deleted function ‘Point2D& Point2D::operator=(const Point2D&)’

Другое утверждение является объявлением функции:

const Point2d findMagicPoint();

Тип возвращаемого значения не обязательно должен быть constпотому что это все равно значение, которое нельзя изменить. например findMagicPoint() = <something>; плохо сформирован.

1

Оба будут работать.

Скорее всего, между ними нет разницы в производительности, так как getX() а также getY() оптимизируется до «ничего». [Вы, вероятно, хотите использовать return y; в GetY tho ‘, это может помочь устранить ошибку или два].

Это в основном вопрос стиля.

Конечно, вы, вероятно, также будете иметь non-const версия этого класса, для тех случаев, когда вы хотите сделать вычисления по точке перед ее использованием.

0

Я не уверен, может ли быть предоставлен факт для этого вопроса, но, по моему мнению, использование get и set для таких небольших объектов, как Point2D, является излишним. Если вы собираетесь использовать эти объекты в качестве констант, просто сделайте их постоянными. Если вы собираетесь использовать их как переменные, просто перегрузите операторы, такие как «+», «+ =» и т. Д., И используйте их. Point2D как элемент данных должен быть инкапсулирован, а не элементы данных Point2D. Опять же, если вы собираетесь использовать их неизменным образом, просто используйте const Point2D, Вы можете изменить (использовать изменяемым образом) данные Point2D позже. Постоянные члены данных не служат цели для этого класса.

0
По вопросам рекламы [email protected]