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

У меня есть абстрактный виртуальный базовый класс Foo, из которого я получаю множество других классов, которые немного отличаются. У меня есть фабрика, которая создает производные классы и возвращает Foo*. Одна из моих больших проблем заключается в перегрузках операторов, мне нужно убедиться, что DFoo не управляется DFoo1 (не показано). В настоящее время я справлялся с этим, проверяя, не сбой ли приведения, но я очень недоволен таким подходом. Я должен использовать базовую реализацию, потому что я могу вернуть только базовый класс с завода. Если это лучший способ сделать это, все в порядке, я просто хочу убедиться, что это имеет смысл и что нет шаблона, который я упускаю. Любые предложения о том, как обращаться с такими вещами, очень ценятся.

 class Foo
 {
    public:
          Foo(int x){...};
          Bar m_bar;
          virtual Foo& operator=(const Foo& f)
          {
             m_bar = f.m_bar
          }
 }

Теперь мой производный класс

class DFoo : public Foo
{
     DFoo(int x, int y):Foo(int x) {...}
     FooBar m_foobar;

     Foo& operator=(const Foo& rhs)
     {
        if(this != &rhs)
        {

              Foo::operator=(rhs);
              DFoo temp = static_cast<DFoo>(rhs);

              if(temp != NULL)
              {
                m_foobar = static_cast<DFoo>(rhs).m_foobar;
              }
              else
                 throw exception(ex);
        }
     }
}

person Steve    schedule 07.01.2010    source источник
comment
Честно говоря, если бы мне нужно было реализовать operator=() для иерархии классов, я бы еще раз взглянул на свой дизайн.   -  person    schedule 07.01.2010
comment
Этот код не делает то, что вы описываете. Я думаю, вы намеревались использовать dynamic_cast и DFoo & вместо того, что вы написали.   -  person Nick Meyer    schedule 07.01.2010
comment
что делает if(temp != NULL)? temp не является указателем, а если бы и был, то исходит из ссылки и не может быть NULL.   -  person Potatoswatter    schedule 07.01.2010


Ответы (3)


Вероятно, вы ищете boost::noncopyable.

person Nikolai Fetissov    schedule 07.01.2010

Самое разумное, что можно сделать в этой ситуации, — объявить операторы присваивания и конструкторы копирования, но не определять их. Затем, если где-то в вашем коде кто-то попытается сделать копию, это вызовет ошибку компоновщика. По сути, это тот же эффект, что и у boost::nocopyable, за исключением того, что вы не используете внешнюю библиотеку для такой простой и тривиальной задачи.

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

person Beanz    schedule 07.01.2010

Вы никогда не должны делать это:

 class DFoo
 {
     Foo& operator=(const Foo& rhs) ;
 };

Если вы явно не хотите поддерживать присваивание базового класса производному типу (маловероятно).
Оператор assignemtn должен выглядеть следующим образом:

 class DFoo
 {
     DFoo& operator=(DFoo const& rhs);  // You can only assign DFoo to a DFoo.
                                        // Now there is no way for DFoo1 to get assigned to a DFoo
 };

Кроме того, в этом тривиальном примере, который вы опубликовали, оператор присваивания по умолчанию, сгенерированный компилятором, должен работать должным образом. Есть ли какая-то особая причина, по которой вы пишете оператор присваивания?

person Martin York    schedule 07.01.2010