оператор виртуального присваивания производного класса не вызывается

Я новичок в C ++ и пытаюсь разобраться с виртуальным назначением. Приведенная ниже программа состоит из абстрактного базового класса с двумя членами данных и производного класса с одним. Когда я устанавливаю абстрактный указатель на производный объект, программа использует абстрактную версию оператора =, а не производную версию, даже если они оба объявлены «виртуальными». Что я здесь делаю не так?

Заранее спасибо,

Джей

#include <iostream>
#include <cstring>

class Abstract
{
  protected:
        char * label;
        int rating;
    public:
        Abstract(const char * l = "null", int r = 0);
        virtual Abstract & operator=(const Abstract & rs);
        virtual ~Abstract() { delete [] label; }
        virtual void view() const = 0;

};

class Derived : public Abstract
{
    private:
        char * style;
    public:
        Derived(const char * s = "none", const char * l = "null",
                  int r = 0);
        ~Derived() { delete [] style; }
        virtual Derived & operator=(const Derived & rs);
        virtual void view() const;

};

Abstract::Abstract(const char * l , int r )
{
    label = new char[std::strlen(l) + 1];
    std::strcpy(label, l);
    rating = r;
}

Abstract & Abstract::operator=(const Abstract & rs)
{
    if (this == &rs)
            return *this;
    delete [] label;
    label = new char[std::strlen(rs.label) + 1];
    std::strcpy(label, rs.label);
    rating = rs.rating;
    return *this;
}

Derived::Derived(const char * s, const char * l, int r)
         : Abstract(l, r)
{
    style = new char[std::strlen(s) + 1];
    std::strcpy(style, s);
}

Derived & Derived::operator=(const Derived & hs)
{
    if (this == &hs)
        return *this;
    Abstract::operator=(hs);
    style = new char[std::strlen(hs.style) + 1];
    std::strcpy(style, hs.style);
    return *this;
}

void Derived::view() const
{
    std::cout << "label: " << label << "\nrating: "
              << rating << "\nstyle: " << style;
}

int main ()
{
    using namespace std;
    char label[20], style[20];
    int rating;


    cout << "label? ";
    cin >> label;
    cout << "rating? ";
    cin >> rating;
    cout <<"style? ";
    cin >> style;

    Derived a;
    Abstract * ptr = &a;
    Derived b(style, label, rating);
    *ptr = b;
    ptr->view();

    return 0;
}

person planarian    schedule 30.10.2011    source источник
comment
Не связано, но почему вы используете char*s?   -  person Mat    schedule 30.10.2011
comment
Не вдаваясь в подробности, вы делаете это неправильно. Прочтите learncpp.com/cpp- tutorial / и поищите в Google оператор виртуального назначения. Об этом уже много говорили.   -  person Seth Carnegie    schedule 30.10.2011
comment
Чтобы код был короче, я попытался удалить вещи, которые не имели отношения к моему вопросу, включая динамическую память (отсюда char * s)   -  person planarian    schedule 30.10.2011
comment
Привет, Сет, я уже провел много времени в поиске в Google (и на этом сайте). Я уже видел страницу, на которую вы ссылаетесь.   -  person planarian    schedule 30.10.2011
comment
Виртуальное поведение вызывается только через указатели или ссылки. Вы пытаетесь заставить его работать с реальным объектом, но этого не происходит. Также, отвечая кому-то, поместите @ [имя] в свой комментарий, где [имя] заменено именем человека, которому вы хотите ответить (скобки также снимаются).   -  person Seth Carnegie    schedule 30.10.2011
comment
@Seth: Но присвоение * ptr = b. Если это не считается указателем, я не понимаю, что вы имеете в виду.   -  person planarian    schedule 30.10.2011
comment
Часть *ptr разыменовывает указатель, чтобы получить реальный объект, затем вызывает operator= для объекта. Поиск виртуального метода не выполняется.   -  person Seth Carnegie    schedule 30.10.2011
comment
Это тот ответ, который я искал. Спасибо!   -  person planarian    schedule 30.10.2011


Ответы (2)


C ++ не позволяет заменять виртуальные функции ковариантными типами параметров. Ваш производный оператор вообще не переопределяет абстрактный оператор присваивания, он определяет полностью ортогональный оператор, связанный только с тем же именем оператора.

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

person Mark B    schedule 30.10.2011
comment
Также очень полезно. Спасибо. - person planarian; 30.10.2011

Это немного устарело, но на случай, если кто-то еще наткнется на это:

Чтобы добавить к ответу Марка, вы можете сделать это, реализовав

Derived & operator=(const Abstract & rs);

В этом случае вам может потребоваться использовать rs путем преобразования: dynamic_cast<const Derived &>(rs)
Конечно, это следует делать только осторожно. Полная реализация будет:

Derived & Derived::operator=(const Abstract & hs)
{
    if (this == &hs)
        return *this;
    Abstract::operator=(hs);
    style = new char[std::strlen(dynamic_cast<const Derived &>(hs).style) + 1];
    std::strcpy(style, dynamic_cast<const Derived &>(hs).style);
    return *this;
}
person user1756254    schedule 11.10.2013