@Robotex

Как правильно переопределить оператор присваивания с инициализацией методов классов-родителей?

Реализовываю копирующие конструкторы и операторы присваивания. И если с конструктором все просто и элегантно:
GravitySource::GravitySource(const GravitySource &obj)
    : MovableObject(obj) // инициализируем родительский класс
{
    setRadius(obj.radius());  // инициализируем новые поля
}


то с оператором присваивания выходит жуть:
GravitySource &GravitySource::operator=(const GravitySource &obj)
{
    if(this != &obj) {
        setRadius(obj.radius());
        setParent(obj.parent());
        setPos(obj.pos());
        setMass(obj.mass());
        setSpeedVector(obj.speedVector());
        setAccelerationVector(obj.accelerationVector());
        setDirectionVector(obj.directionVector());
        setGravityVector(obj.gravityVector());
        setDirectionAngle(obj.directionAngle());
        setMaxAcceleration(obj.maxAcceleration());
    }

    return *this;
}

И тут еще не так страшно, но если в классе будет 100 полей (с учетом всех родителей)? Есть ли такой же элегантный способ инициализировать поля класса в операторе присваивания, как в копирующем конструкторе?
  • Вопрос задан
  • 519 просмотров
Пригласить эксперта
Ответы на вопрос 2
maaGames
@maaGames
Погроммирую программы
GravitySource &GravitySource::operator=(const GravitySource &obj)
{
    if(this != &obj) {
        *((MovableObject*)this) = obj;
        setRadius(obj.radius());
       }

    return *this;
}


А ещё лучше через функцию обмена, которую надо не забыть реализовать:
GravitySource &GravitySource::operator=(const GravitySource &obj)
{
       GravitySource temp(obj);
       this->Swap( temp );
       return *this;
 }
Ответ написан
@Mercury13
Программист на «си с крестами» и не только
Попытайтесь выяснить, кто не терпит тупого поэлементного копирования, и изолировать их. Либо в один маленький объектик, либо в один маленький уровень наследования.

Вариант 1. Сделать промежуточный уровень наследования, в который вносим некопируемые части.

class LevelObject
{
private:
   Level& level;  // Сцылка на уровень, по определению неизменная
   int x, y;           // Присваивать.
}


Разбиваем на две части (внимание! — конструктор копирования для простоты не прописан, вероятно, потребуется и он):
#include <iostream>

class Level
{
public:
    int value;
    Level(int aValue) : value(aValue) {}
};

class LevelChild
{
protected:
    Level& level;  // не присваивать
public:
    LevelChild(Level& aLevel) : level(aLevel) {}
    LevelChild operator=(LevelChild&) { return *this; }   // ничего не делающая операция «присвоить»
};

class LevelObject: public LevelChild
{
protected:
    int x, y;
public:
    LevelObject(Level& aLevel, int aX, int aY) : LevelChild(aLevel), x(aX), y(aY) {}
    void print();
};

void LevelObject::print()
{
    std::cout << "(" << x << ", " << y << ") at level " << level.value << std::endl;
}

int main()
{
    Level l1(1);  LevelObject o1(l1, 1, 2);
    Level l2(2);  LevelObject o2(l2, 3, 4);
    o1.print();
    o2.print();
    o2 = o1;
    o2.print();
}


Вариант 2. Сделать маленькие объекты-функции со своими операциями присваивания.

class LevelObject
{
private:
   Level* level;  // На сей раз уже копируется
   Array3 pos;    // Какой-то инкапсулированный объект-массив
   std::wstring name;   // тоже инкапсулированный объект
}


И всё, когда для std::wstring и Array3 корректно прописаны операции присваивания, для LevelObject всё будет работать корректно без единой строчки.

P. S. А точно ваш объект страдает от поэлементного копирования и нужна своя операция?
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы