Вопрос

У меня проблемы с наследством оператора =. Почему этот код не работает, а какой лучший способ исправить это?

#include <iostream>

class A
{
public:
    A & operator=(const A & a)
    {
        x = a.x;
        return *this;
    }

    bool operator==(const A & a)
    {
        return x == a.x;
    }

    virtual int get() = 0; // Abstract

protected:
    int x;
};

class B : public A
{
public:
    B(int x)
    {
        this->x = x;
    }

    int get()
    {
        return x;
    }
};

class C : public A
{
public:
    C(int x)
    {
        this->x = x;
    }

    int get()
    {
        return x;
    }
};

int main()
{
    B b(3);
    C c(7);
    printf("B: %d C: %d B==C: %d\n", b.get(), c.get(), b==c);

    b = c; // compile error
    // error: no match for 'operator= in 'b = c'
    // note: candidates are B& B::operator=(const B&)

    printf("B: %d C: %d B==C: %d\n", b.get(), c.get(), b==c);
    return 0;
}
Это было полезно?

Решение

Если вы не объявите оператора присваивания копирования в классе, компилятор неявно объявит один для вас. Неявно объявленное оператору присваивания копирования будет Спрятать Любые унаследованные операторы назначения (читайте о «Скрытие имени» в C ++), что означает, что любые унаследованные операторы назначения станут «невидимым» неквалифицированный Имя поиска процесса (который происходит, когда вы делаете b = c), если вы не предпринимаете определенные шаги, чтобы «показать их».

В вашем случае класс B не имеет явного объявленного оператора копирования-присваивания. Что означает, что компилятор объявит

B& B::operator =(const B&)

неявно. Это будет скрывать оператор, унаследованный от A. Отказ Линия

b = c;

не скомпилируется, потому что единственный кандидат здесь - это вышесказанное B::operator = (Компилятор уже говорил вам об этом); Все остальные кандидаты скрыты. И с тех пор c не конвертируется для B&, Вышеуказанное назначение не компилируется.

Если вы хотите, чтобы ваш код был компитенным, вы можете использовать использование-декларацию, чтобы показать унаследовано A::operator = добавляя

using A::operator =;

к определению класса B. Отказ Код теперь будет скомпилировать, хотя это не будет хорошим стилем. Вы должны иметь в виду, что в этом случае b = c Присвоение будет вызвать A::operator =, который назначает только A Части вовлеченных объектов. (Но, очевидно, это ваше намерение.)

Альтернативно, в таких случаях, вы всегда можете работать вокруг имени, скрывающиеся с помощью квалифицированный версия имени

b.A::operator =(c);

Другие советы

Что происходит, это то, что по умолчанию operator = что компилятор генерирует для любого класса, у которого нет, скрывает базовый класс operator =. Отказ В этом конкретном случае компилятор генерирует const B &B::operator =(const B &) для вас за кулисами. Ваше задание соответствует этому оператору и полностью игнорирует тот, который вы объявили в class A. Отказ С А. C& не может быть преобразован в B& Компилятор генерирует ошибку, которую вы видите.

Вы хотите, чтобы это произошло, даже если сейчас кажется неприятным. Это предотвращает, как вы написали с работы. Вы не хотите, чтобы код не хотел работать, потому что он позволяет не связанным типам (B и C иметь общего предка, но единственным важным отношениям в наследовании являются родительские отношения для детей -> вкусных отношений, а не родственные отношения), которые могут быть назначены Другой.

Подумайте об этом с точки зрения ISA. Должен а. Car разрешено быть назначенным Boat только потому, что они оба Vehicles?

Чтобы сделать что-то вроде этой работы, вы должны использовать Конверт / письмо шаблон. Конверт (рукоятка AKA) является специализированным классом, который является единственной работой, в которой есть только работа, это удерживать экземпляр некоторых класс, который получен из определенного базового класса (буква). Ручка пересылает все операции, но назначение на содержащийся объект. Для назначения он просто заменяет экземпляр внутреннего объекта с помощью копирования (используя метод «клона» (виртуальный конструктор AKA))) копия назначенного от объекта.

Вы не можете назначить подобную иерархию, подобную этой - B и C - это различные подклассы A. Вы можете назначить B до B или C к C, но не C до B или наоборот.

Вы, вероятно, хотите реализовать operator= в B и C, делегируя часть задания A::operator= Прежде чем попробовать это, хотя. В противном случае B- и C-специфические части этих классов будут потеряны в назначении.

Обычно оператор = определяется в B как

B& operator=(B const &);

Поскольку B - не однозначная и доступная база «C», преобразование от C до B не допускается компилятором.

Если вы действительно хотите, чтобы «C» был назначен на «B», «B» должен поддерживать соответствующее оператор назначения как

B& operator=(C const &);

(Вероятно, не исправьте и, вероятно, не то, что вы должны сделать), но ... есть способ заставить проблему, если вы действительно должны:

 (A&)(*(&b)) = (A&)(*(&c))
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top