Допустим, есть некий класс X, в общем случае производный от каких-то еще классов. Как определить можно ли объекты класса X присваивать друг другу:
X f();
X x;
x = f();
Правильно ли я понимаю, что для этого нужно просмотреть определение класса X и всех его базовых классов и убедиться, что в каждом из них имеется либо реализованный operator= либо корректно работающий дефолтный operator= ?
+ Аналогичный вопрос про конструирование копированием:
On 24.04.2011 15:31, Максим Рогожин wrote:
> Допустим, есть некий класс X, в общем случае производный от каких-то еще > классов.
Для начала нужно сказать, что для operator = не может быть динамического
полиморфизма в рантайме. Т.е. как бы operator = никогда не "виртуальный".
Ну т.е. динамический полиморфизм работать не будет.
Как определить можно ли объекты класса X присваивать друг другу: > > X f(); > X x; > x = f();
Если есть публичный X::operator = — можно будет присваивать
> Правильно ли я понимаю, что для этого нужно просмотреть определение класса X и > всех его базовых классов
Без базовых. В этом классе только. Хотя как написать код ... да, может и базовые
надо глядеть.
и убедиться, что в каждом из них имеется либо > реализованный operator= либо корректно работающий дефолтный operator= ?
Да.
> > + Аналогичный вопрос про конструирование копированием: > > void g(X); > X x; > g(x);
То же самое, только если есть публичный X::X( const X& )
Ну или если есть дефолтные предоставляемые компилятором.
Здравствуйте, Максим Рогожин, Вы писали:
МР>Допустим, есть некий класс X, в общем случае производный от каких-то еще классов. Как определить можно ли объекты класса X присваивать друг другу:
Думаю, формализовать можно примерно так:
Если в классе определен открытый оператор копирующего присваивания, то копирующее присваивание разрешено;
Если в классе оператор копирующего присваивания объявлен закрытым, то копирующее присваивание запрещено;
Если в классе оператор копирующего присваивания не объявлен, то копирующее присваивание разрешено во всех случаях, кроме следующих:
В классе содержатся нестатические члены-ссылки;
В классе содержатся нестатические члены, для которых запрещено копирующее присваивание;
Для какого-либо из непосредственных базовых классов запрещено копирующее присваивание.
Разрешено ли копирующее присваивание для каждого базового класса определяем, разумеется, по этим же правилам.
Правила для копирующих конструкторов будут выглядеть аналогично.
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, MasterZiv, Вы писали:
MZ>On 24.04.2011 15:31, Максим Рогожин wrote:
>> Допустим, есть некий класс X, в общем случае производный от каких-то еще >> классов.
MZ>Для начала нужно сказать, что для operator = не может быть динамического MZ>полиморфизма в рантайме. Т.е. как бы operator = никогда не "виртуальный". MZ>Ну т.е. динамический полиморфизм работать не будет.
class A
{
public:
virtual A & operator = (const A &);
};
class B : public A
{
public:
virtual A & operator = (const A &);
};
int main()
{
B b;
A & ra = b;
B c;
ra = c;
}
Of course, the code must be complete enough to compile and link.
Спасибо всем за ответы! Но, я немного другое хотел спросить, я хотел спросить как определить что присваивание будет корректно. Например:
class A {
// только дефолтный operator=
A() {_buff = new int[1024];}
~A(){ delete _buff;}
private:
int* _buff;
};
class B : public A {
// только дефолтный operator=private:
std::string _name;
};
Глядя только на класс B можно подумать, что объекты B можно присваивать друг другу. Но в базовом классе operator= будет некорректно работать с _buff; (просто указатель скопирует).
Здравствуйте, Максим Рогожин, Вы писали:
МР>Спасибо всем за ответы! Но, я немного другое хотел спросить, я хотел спросить как определить что присваивание будет корректно. Например:
МР>
МР>class A {
МР>// только дефолтный operator=
МР>A() {_buff = new int[1024];}
МР>~A(){ delete _buff;}
МР>private:
МР> int* _buff;
МР>};
МР>class B : public A {
МР>// только дефолтный operator=
МР>private:
МР> std::string _name;
МР>};
МР>
МР>Глядя только на класс B можно подумать, что объекты B можно присваивать друг другу. Но в базовом классе operator= будет некорректно работать с _buff; (просто указатель скопирует).
Эту проблему должен решать разработчик класса A, а не пользователь. Разработчик должен либо реализовать копирование корректно (у него просто уйма вариантов сделать это), либо запретить копирование вовсе.
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>Здравствуйте, MasterZiv, Вы писали:
MZ>>On 24.04.2011 15:31, Максим Рогожин wrote:
>>> Допустим, есть некий класс X, в общем случае производный от каких-то еще >>> классов.
MZ>>Для начала нужно сказать, что для operator = не может быть динамического MZ>>полиморфизма в рантайме. Т.е. как бы operator = никогда не "виртуальный". MZ>>Ну т.е. динамический полиморфизм работать не будет.
L_L>[ccode] L_L>class A L_L>{ L_L>public: L_L> virtual A & operator = (const A &); L_L>};
L_L>class B : public A L_L>{ L_L>public: L_L> virtual A & operator = (const A &); L_L>};
Здравствуйте, Максим Рогожин, Вы писали:
МР>Спасибо всем за ответы! Но, я немного другое хотел спросить, я хотел спросить как определить что присваивание будет корректно. Например: МР>Глядя только на класс B можно подумать, что объекты B можно присваивать друг другу. Но в базовом классе operator= будет некорректно работать с _buff; (просто указатель скопирует).
Это демонстрация того, что твое утверждение про невозможность динамического полиморфизма для оператора присваивания — не всегда верно. Полиморфизм есть. Динамический.
Of course, the code must be complete enough to compile and link.
On 24.04.2011 20:14, Lorenzo_LAMAS wrote:
> Это демонстрация того, что твое утверждение про невозможность динамического > полиморфизма для оператора присваивания — не всегда верно. Полиморфизм есть. > Динамический.
Да, есть. На одну половину стороны присваивания
Да не, можно и в базовом классе объявить все возможные варианты
присваивания справа от = в виде виртуальных методов,
да толку-то... мало того, что ВСЕ классы в иерархии должны быть
заранее известны и перечислены в базовом классе, так ещё если
что добавится -- нужно ВО ВСЕХ классах переопределять метод.
А так -- нормально, полный динамический полиморфизм.
Здравствуйте, MasterZiv, Вы писали:
MZ>А так -- нормально, полный динамический полиморфизм.
Можно NVI заюзать, если так уж приспичило. Но главная проблема тут в другом. Не понятно, что делать, если хотят присвоить груше яблоко...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, MasterZiv, Вы писали:
MZ>On 24.04.2011 20:14, Lorenzo_LAMAS wrote:
>> Это демонстрация того, что твое утверждение про невозможность динамического >> полиморфизма для оператора присваивания — не всегда верно. Полиморфизм есть. >> Динамический.
MZ>А так -- нормально, полный динамический полиморфизм.
С этим нужно быть поаккуратнее, чтоб не получать сюрпризы.
Пример:
#include <iostream>
class A
{
public:
virtual A& operator=(const A&)
{
std::cout << "A::operator=" << std::endl;
return *this;
}
};
class B : public A
{
public:
virtual B& operator=(const A&)
{
std::cout << "B::operator=" << std::endl;
return *this;
}
};
int main()
{
B b;
A& ar = b;
B& br = b;
ar = A(); //Output: "B::operator="
b = B(); //Output: "A::operator="
}
Обратите внимание на последние строки программы. Когда копирующее присваивание выполняется через ссылку на объект A, вызывается B::operator= — т.е. работает тот самый полиморфизм, как и ожидалось. А когда копирующее присваивание выполняется непосредственно объекту производного класса, то полиморфизм куда-то вдруг "исчезает" и вызывается оператор копирующего присваивания базового класса. А происходит это потому, что оператор присваивания, определенный в производном классе, не является копирующим. Поэтому компилятор вынужден самостоятельно сгенерировать копирующий оператор присваивания, из которого вызывается копирующий оператор присваивания базового класса. Короче говоря, никогда не стоит забывать о том, что далеко не каждый оператор присваивания является копирующим.
--
Не можешь достичь желаемого — пожелай достигнутого.