Как назначить объект данных с постоянными членами?

Надеюсь, это не дубликат. Если это так, пожалуйста, укажите мне это в комментарии, и я снова удалю вопрос.

У меня есть объект данных с данными, которые действительны только в комплекте — то есть нет смысла изменять значение одного члена без аннулирования других членов.
Этот объект данных описывает некоторую информацию об изображении:

struct ImageInfo
{
ImageInfo(const double &ppix, ...)
: PpiX(ppix),
...
{ }

const double PpiX;
const double PpiY;
const int SizeX;
const int SizeY;
};

В моем изображении объекта у меня есть неконстантная член типа ImageInfo:

class MyImageObject
{
...
private:
ImageInfo mMyInfo;
}

Я хочу быть в состоянии изменить mMyInfo во время выполнения, но только для того, чтобы он принял новый экземпляр ImageInfo (…).

в MyImageObject::Load() функция, я хотел бы прочитать эти данные из файла информации, а затем создать ImageInfo экземпляр с правильным набором данных:

double ppix = ImageFile.GetPpiX();
...
mMyInfo = ImageInfo(ppix, ...);

Но мне не удалось написать правильный оператор присваивания (конечно, возможен конструктор копирования). Мое решение осталось mMyInfo пусто, потому что я не ссылался this:

ImageInfo operator=(const ImageInfo &other)
{
// no reference to *this
return ImageInfo(other);
}

Из любопытства я хотел бы знать, как должен выглядеть оператор присваивания для такого класса.

Я использую простой C ++.

РЕДАКТИРОВАТЬ
Возможные решения (цель состоит в том, чтобы сохранить данные переносимыми, но согласованными):

  • Используйте частных пользователей вместе с Get...() функции -> просто, но я бы хотел избежать скобок.
  • Сохраните указатель на ImageInfo: ImageInfo *mpMyInfo; (Я хотел бы избежать кучи.)
  • Используйте сериализацию и сохраните сериализованный ImageInfo, затем создайте локальные экземпляры из сериализованных данных.

2

Решение

Я не думаю, что вы можете иметь константные переменные-члены, которые не являются статичными. Если вам нужны переменные const, которые изменяются вместе с экземпляром, вы можете сделать что-то вроде этого:

struct ImageInfo
{
private:
double myPpiX;
double myPpiY;
int mySizeX;
int mySizeY

public:
ImageInfo(const double &ppix, ...)
: myPpiX(ppix),
PpiX(myPpiX),
...
{ }

ImageInfo( const ImageInfo &other)
: myPpiX( other.myPpiX),
PpiX(myPpiX)
...
{ }

const double &PpiX;
const double &PpiY;
const int &SizeX;
const int &SizeY;

// EDIT: explicit assignment operator was missing
ImageInfo& operator=(const ImageInfo &other)
{
myPpiX  = other.myPpiX;
myPpiY  = other.myPpiX;
mySizeX = other.mySizeX;
mySizeX = other.mySizeX;
return *this;
}
};

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

3

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

Так как они являются полями данных, которые могут быть изменены, они не являются const,

Если вы хотите ограничить доступ пост-конструкции к ним constВам нужно обернуть их в аксессоры следующим образом:

struct ImageInfo
{
ImageInfo(const double &ppix, /*...*/)
: PpiX_(ppix),
/*...*/
{ }
double const& PpiX() const {return PpiX_; };
double const& PpiY() const {return PipY_; };
int const& SizeX() const {return SizeX_; };
int const& SizeY() const {return SizeY_; };
private:
double PpiX_;
double PpiY_;
int SizeX_;
int SizeY_;
};

Это позволяет перемещать / копировать назначение и конструкцию, блокируяconst доступ за пределы указанной конструкции.

Избегать () это сложно, но может быть сделано с псевдо-ссылками, что-то вроде этого:

struct pseudo_const_reference_to_Ppix {
ImageInfo const* self;
operator double() const { return self->Ppix; }
void reseat( ImageInfo const* o ) { self = o; }
};

плюс целая куча шаблонов, чтобы перегрузить каждый const оператор слева и справа так, что выше pseudo_const_reference_* так же действует, как double,

Общие версии могут быть написаны (либо с помощью функтора или std::function если вы готовы страдать от стирания типа накладных расходов).

Затем вы поддерживаете эти псевдо-const справки о назначении и копировании / перемещении конструкции.

я думаю () это лучший вариант.

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

2

Если что-то постоянное, вы не можете это изменить. Полная остановка.

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

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

Альтернативой является косвенное использование mMyInfo, скажем, с использованием unique_ptr, тогда вы можете заменить его другим экземпляром. Я бы не стал этого делать без веской причины.

1

Неизменная ценность объектов велика. Но переменная, содержащая объект значения (mMyInfo в MyImageObject), должна быть (неконстантной) указателем. В других языках (например, Java) это происходит автоматически, но не в C ++, где вам нужен оператор *. Кроме того, нет необходимости переопределять / реализовывать оператор = для объектов-значений. Чтобы изменить данные изображения в объекте изображения, вы назначаете вновь созданный объект ImageInfo указателю myImageInfo. Таким образом, ни одна из внутренних переменных объекта значения не изменяется.

0