Конструкторы и операторы копирования и перемещения наследуемого класса

134
21 апреля 2022, 15:50

Мой вопрос заключается в том, правильно ли реализована логика копирования и перемещения конструкторов и операторов наследуемого класса.

Пример реализации:

Класс ExampleOne

class ExampleOne
{
public:
    
    ExampleOne(void);
    ExampleOne& operator=(const ExampleOne& other);
    ExampleOne& operator=(ExampleOne&& other);
    ExampleOne(const ExampleOne& other);
    ExampleOne(ExampleOne&& other);
    virtual ~ExampleOne(void) = default;
    
public:
    
    int     val1{ -1 };
    int     val2{ -1 };
    QString str1;
};
ExampleOne& ExampleOne::operator=(const ExampleOne& other)
{
    if (&other != this) {
        val1 = other.val1;
        val2 = other.val2;
        str1 = other.str1;
    }
    return *this;
}
        
ExampleOne& ExampleOne::operator=(ExampleOne&& other)
{
    if (&other != this) {
        val1 = other.val1;
        val2 = other.val2;
        str1 = std::move(other.str1);
    }
    return *this;
}
        
ExampleOne::ExampleOne(const ExampleOne& other)
{
    if (&other != this) {
        val1 = other.val1;
        val2 = other.val2;
        str1 = other.str1;
    }
}
        
ExampleOne::ExampleOne(ExampleOne&& other)
{
    if (&other != this) {
        val1 = other.val1;
        val2 = other.val2;
        str1 = std::move(other.str1);
    }
}
ExampleOne::ExampleOne(void) 
    : val1(-1)
    , val2(-1)
    , str1(QString())
{
    
}

Класс ExampleTwo

class ExampleTwo : public ExampleOne
{
public:
    
    ExampleTwo(void);
    ExampleTwo& operator=(const ExampleTwo& other);
    ExampleTwo& operator=(ExampleTwo&& other);
    ExampleTwo(const ExampleTwo& other);
    ExampleTwo(ExampleTwo&& other);
    virtual ~ExampleTwo(void) = default;
    
public:
    
    int     val3{ -1 };
    QString str2;
};
ExampleTwo& ExampleTwo::operator=(const ExampleTwo& other)
{
    ExampleOne::operator=(other);
    if (&other != this) {
        val3 = other.val3;
        str2 = other.str2;
    }
    return *this;
}
        
ExampleTwo& ExampleTwo::operator=(ExampleTwo&& other)
{
    ExampleOne::operator=(other);
    if (&other != this) {
        val3 = other.val3;
        str2 = std::move(other.str2);
    }
    return *this;
}
        
ExampleTwo::ExampleTwo(const ExampleTwo& other)
{
    ExampleOne::operator=(other);
    if (&other != this) {
        val3 = other.val3;
        str2 = other.str2;
    }
}
        
ExampleTwo::ExampleTwo(ExampleTwo&& other)
{
    ExampleOne::operator=(other);
    if (&other != this) {
        val3 = other.val3;
        str2 = std::move(other.str2);
    }
}
ExampleTwo::ExampleTwo(void) 
    : ExampleOne()
    , val3(-1)
    , str2(QString())
{
    
}

Если нет, то как правильно реализовать логику копирования и перемещения у наследуемого класса. Важно, что в реализации логики копирования и перемещения у наследуемого класса нужно использовать сначала логику копирования и перемещения у родительского класса и только после этого, если требуется, реализовать собственную логику.

Answer 1

Почти всё ок, только вот несколько моментов:

  1. В конструкторах копирования (с перемещением и без) не нужна проверка со сравнением адресов.
  2. В констукторах копирования (с перемещением и без) класса-наследника нужно вызывать констукторы класса-предка вместо оператора присваивания.
  3. Для инициализации членов используйте список инициализации в конструкторах.
  4. В операторах присваивания класса-наследника вызвайте оператор присваивания класса-предка внутри if.
ExampleOne::ExampleOne(const ExampleOne& other)
    : val1(other.val1), val2(other.val2), str1(other.str1)
{
}
        
ExampleOne::ExampleOne(ExampleOne&& other)
    : val1(other.val1), val2(other.val2), str1(std::move(other.str1))
{
}
ExampleTwo& ExampleTwo::operator=(const ExampleTwo& other)
{
    if (&other != this) {
        ExampleOne::operator=(other);
        val3 = other.val3;
        str2 = other.str2;
    }
    return *this;
}
        
ExampleTwo& ExampleTwo::operator=(ExampleTwo&& other)
{
    if (&other != this) {
        ExampleOne::operator=(other);
        val3 = other.val3;
        str2 = std::move(other.str2);
    }
    return *this;
}
        
ExampleTwo::ExampleTwo(const ExampleTwo& other) 
    : ExampleOne(other), val3(other.val3), str2(other.str2)
{
}
        
ExampleTwo::ExampleTwo(ExampleTwo&& other)
     : ExampleOne(other), val3(other.val3), str2(std::move(other.str2))
{
}
READ ALSO
Как наиболее точно измерить потребляемую программой память?

Как наиболее точно измерить потребляемую программой память?

Как наиболее точно измерить потребляемую программой память?

129
не работает max_element

не работает max_element

почему max_element работает неправильно ?

118
Чтение данных, записанных через пробелы из файла в C++

Чтение данных, записанных через пробелы из файла в C++

Есть простейшая задача - дан массив оценок, из которого нужно удалить двойки, удвоить пятёрки и сортировать оценки по возрастаниюЗадача решена...

139
не работает qsort c++

не работает qsort c++

код должен сортировать числа, но выдаёт ошибку

130