Надеюсь, это не дубликат. Если это так, пожалуйста, укажите мне это в комментарии, и я снова удалю вопрос.
У меня есть объект данных с данными, которые действительны только в комплекте — то есть нет смысла изменять значение одного члена без аннулирования других членов.
Этот объект данных описывает некоторую информацию об изображении:
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 *mpMyInfo;
(Я хотел бы избежать кучи.)Я не думаю, что вы можете иметь константные переменные-члены, которые не являются статичными. Если вам нужны переменные 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.
Так как они являются полями данных, которые могут быть изменены, они не являются 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
из которого они вызываются, даже несмотря на то, что на сайте доступа это ясно, как день.
Если что-то постоянное, вы не можете это изменить. Полная остановка.
Таким образом, вы должны где-то скорректировать дизайн, либо не иметь этих членов ImageInfo const, либо не иметь ImageInfo в качестве члена, либо лучше всего: не выполнять назначение.
Обычно константные члены задаются в конструкторе. Вы можете создать функцию загрузки, которая создает объект MyImageObject со всем его содержимым, поэтому избегайте полузадачи и загружайте содержимое на втором этапе.
Альтернативой является косвенное использование mMyInfo, скажем, с использованием unique_ptr, тогда вы можете заменить его другим экземпляром. Я бы не стал этого делать без веской причины.
Неизменная ценность объектов велика. Но переменная, содержащая объект значения (mMyInfo в MyImageObject), должна быть (неконстантной) указателем. В других языках (например, Java) это происходит автоматически, но не в C ++, где вам нужен оператор *. Кроме того, нет необходимости переопределять / реализовывать оператор = для объектов-значений. Чтобы изменить данные изображения в объекте изображения, вы назначаете вновь созданный объект ImageInfo указателю myImageInfo. Таким образом, ни одна из внутренних переменных объекта значения не изменяется.