Почему не вызывается мой оператор присваивания? - PullRequest
1 голос
/ 11 сентября 2011

Я в замешательстве ... почему мой оператор присваивания не вызывается здесь?

template<typename This>
struct mybase
{
    This& operator =(const This &other)
    {
        __debugbreak();  // The debugger should break here, but doesn't.
        return static_cast<This &>(*this):
    }
};

struct myderived : mybase<myderived>
{
    int x;
};

int main()
{
    myderived a = myderived();  // And yes, I know it's redundant...
    myderived b = myderived();
    a = b;

    return 0;
}

Ответы [ 4 ]

6 голосов
/ 11 сентября 2011

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

5 голосов
/ 11 сентября 2011

mybase::operator= является скрытым автоматически сгенерированным оператором назначения копирования myderived::operator=.

Вы можете использовать объявление using, чтобы сделать оператор базового класса видимым в производном классе.

РЕДАКТИРОВАТЬ: добавлен пример для запроса:

template<typename This>
struct mybase
{
    This& operator =(const This &other)
    {
        //__debugbreak();  // The debugger should break here, but doesn't.
        return static_cast<This &>(*this);
    }
};

struct myderived : mybase<myderived>
{
    using mybase<myderived>::operator=;
    int x;
};

int main()
{
    myderived a = myderived();  // And yes, I know it's redundant...
    myderived b = myderived();
    a = b;
}

Это прекрасно компилируется с Visual C ++ 10.0 и Comeau Online. Последнее означает на практике, что это хороший стандарт C ++. Однако код не компилируется с MinGW g ++ 4.4.1 (ошибка компилятора).

РЕДАКТИРОВАНИЕ 2: На самом деле, проверяя сейчас, с Visual C ++ 10.0 он компилируется, но оператор базового класса не вызывается. Так что, возможно, G ++ является правильным. using - это обычно способ ввода оператора присваивания базового класса (или чего-либо еще), но в этом случае он имеет ту же сигнатуру, что и производный класс & rsquo; Скопируйте оператор присваивания, и я пока не знаю, является ли поведение Visual C ++ правильным или нет - ndash; это угловой случай языка.

РЕДАКТИРОВАТЬ 3: Я проверил N3290 (стандартный черновик, идентичный C ++ 11), и он говорит

§12.8 / 18:
Если определение класса явно не объявляет оператор присваивания копии, он объявляется неявно. Если определение класса объявляет конструктор перемещения или оператор присваивания перемещения, неявно объявленный оператор присваивания копии определяется как удаленный; в противном случае он определяется как дефолтный (8.4).

Я лично интерпретирую это как высказывание, что с объявлением using класс & ldquo; объявляет & rdquo; оператор присваивания копии, и поэтому его не следует генерировать неявно (как это делает Visual C ++ 10.0). Тем не менее, это угловой случай языка. Другие могут интерпретировать это по-разному, и, как отмечено выше, компиляторы отличаются!

Приветствия и hth.,

3 голосов
/ 11 сентября 2011

Эта строка:

a = b;  

, очевидно, требует, чтобы myderived перегрузил оператор назначения копирования.Он может быть неявно сгенерирован компилятором или явно определен классом myderived:

12.8 Копирование объектов класса [class.copy]

9. Оператор присвоения копии, объявленный пользователем X::operator= - это нестатическая не шаблонная функция-член класса X с ровно одним параметром типа X, X&, const X&,volatile X& или const volatile X&.

Вы попытались создать объявленный пользователем оператор копирования в своем классе mybase, но на самом деле он не является оператором копирования в соответствии со стандартом C ++.Представьте, что мы сделали замену типа для This на myderived:

// Hypothetical class generated by the compiler from
// the mybase template class with This = myderived
struct mybase_myderived 
{
    myderived& operator =(const myderived &other) 
    { 
        // ...
    } 
};

Очевидно, что это не оператор присваивания копии, поскольку параметр other имеет тип const myderived&, а не const mybase&,Если бы параметр other имел тип const mybase&, или mybase, или mybase&, то это был бы действительный оператор назначения копирования, который может вызываться оператором назначения копирования по умолчанию в myderived.Но это не так, поэтому компилятор по-прежнему генерирует оператор назначения копирования по умолчанию для mybase, что, конечно, в этом случае ничего не делает.

Сгенерированный компилятором оператор назначения копирования по умолчанию в myderived вызывает сгенерированный компилятором оператор присваивания по умолчанию в mybase.Так что в итоге происходит, в результате перегрузка operator=(const myderived &other) никогда не вызывается.

Причина, по которой компилятор не просто вызывает mybase::operator= напрямую, заключается в том, что он был скрыт сгенерированным компиляторомскопируйте оператор присваивания в myderived, как указывает Альф П. Штейнбах в этот ответ .

2 голосов
/ 11 сентября 2011

Поскольку компилятор вводит оператор присваивания по умолчанию в myderived.Переопределите его и позвоните своему базовому оператору присваивания.Или, возможно, поможет директива using?Попробуйте использовать mybase :: operator = в теле myderived.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...