Бывают ли нужны virtual operator= ?
От: Максим Рогожин Россия  
Дата: 05.02.18 12:50
Оценка:
Вопросы возникли...
1. Бывают ли нужны виртуальные операторы присваивания?
2. Операторы присваивания рассчитаны только на работу с объектами на стеке, а не в динамической памяти? (Т.е. когда известны типы объектов).
Re: Бывают ли нужны virtual operator= ?
От: rg45 СССР  
Дата: 05.02.18 13:15
Оценка:
Здравствуйте, Максим Рогожин, Вы писали:

МР>Вопросы возникли...

МР>1. Бывают ли нужны виртуальные операторы присваивания?
МР>2. Операторы присваивания рассчитаны только на работу с объектами на стеке, а не в динамической памяти? (Т.е. когда известны типы объектов).

Ну коль скоро операторы присваивания можно определять для выражений совершенно произвольных типоа, отличных от целевого, то вполне закономерно, что такие операторы могут быть виртуальными. Например, абстрактный базовый класс IString вполне мог бы иметь виртуальный оператор присваивания по обычной строке const char*.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re: Бывают ли нужны virtual operator= ?
От: Erop Россия  
Дата: 05.02.18 13:18
Оценка:
Здравствуйте, Максим Рогожин, Вы писали:

МР>1. Бывают ли нужны виртуальные операторы присваивания?

Почему нет? Например может быть оператор присваивания от ОДНОГО И ТОГО ЖЕ объекта.

МР>2. Операторы присваивания рассчитаны только на работу с объектами на стеке, а не в динамической памяти? (Т.е. когда известны типы объектов).


Почему? Внутри оператора присваивания MDT всегда же известен.

Например, представь себе, что у нас есть какая-то система типов, в которых может быть общий путь преобразования, а могут быть какие-то хитрые, оптимизированные.

class CObj1;
class CObj2;
class CObj3;

struct IObj {

    IObj& virtual operator = ( const& IObj obj ) { return obj.AssignTo( this ); }

    IObj& AssignTo( IObj* obj ) const { return doAssignTo( obj ); } 
    
    virtual IObj& AssignTo( CObj2* ) const;// { return doAssignTo( obj ); } 
protected:
    IObj& doAssignTo( IObj* ) const; // реализация обобщённого алгоритма. 

};

struct CObj1 : IObj {
    CObj2 AssignTo( CObj2* obj ) const; // Реализация присваивания CObj1 в CObj2
};

struct CObj2 : IObj {
    virtual CObj2 operator = ( const& IObj obj ) { return obj.AssignTo( this ), *this; }
};

struct CObj3 : IObj {
    CObj2& AssignTo( CObj2* obj ) const; // Реализация присваивания CObj1 в CObj2
};

inline IObj& IObj::AssignTo( CObj2* ) const { return doAssignTo( obj ); }
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Отредактировано 05.02.2018 15:04 Erop . Предыдущая версия .
Re[2]: Бывают ли нужны virtual operator= ?
От: uzhas Ниоткуда  
Дата: 05.02.18 14:14
Оценка:
Здравствуйте, Erop, Вы писали:

E>Например


можешь дать что-то компилируемое? тут даже дело не в прыгающих амперсандах
вот с чего я начал: https://ideone.com/MvnI8F
Re[2]: Бывают ли нужны virtual operator= ?
От: uzhas Ниоткуда  
Дата: 05.02.18 14:18
Оценка:
Здравствуйте, rg45, Вы писали:

R>Например, абстрактный базовый класс IString вполне мог бы иметь виртуальный оператор присваивания по обычной строке const char*.


давай рабочий код и свое мнение, что здесь "бывает нужно"
есть какое-то преимущество перед невиртуальным operator= в соответствующем наследнике MyString : public IString ?
Re[2]: Бывают ли нужны virtual operator= ?
От: Максим Рогожин Россия  
Дата: 05.02.18 14:34
Оценка: 10 (1)
Здравствуйте, Erop, Вы писали:

E>
E>class CObj1;
E>class CObj2;
E>class CObj3;

E>struct IObj {

E>    void operator = ( const& IObj obj ) { obj.AssignTo( this ); }

E>    virtual void operator = ( const& CObj1 obj ) { obj.AssignTo( this ); }
E>    virtual void operator = ( const& CObj3 obj ) { obj.AssignTo( this ); }

E>    void AssignTo( IObj* obj ) const { doAssignTo( obj ); } 
    
E>    virtual void AssignTo( CObj2* ) const;// { doAssignTo( obj ); } 
E>protected:
E>    void doAssignTo( IObj* ) const; // реализация обобщённого алгоритма. 

E>};

E>struct CObj1 : IObj {
E>    void AssignTo( CObj2* obj ) const; // Реализация присваивания CObj1 в CObj2
E>};

E>struct CObj2 : IObj {
E>    virtual void operator = ( const& CObj1 obj ) { obj.AssignTo( this ); }
E>    virtual void operator = ( const& CObj3 obj ) { obj.AssignTo( this ); }
E>};

E>struct CObj3 : IObj {
E>    void AssignTo( CObj2* obj ) const; // Реализация присваивания CObj1 в CObj3
E>};

E>inline void IObj::AssignTo( CObj2* ) const { doAssignTo( obj ); } 

E>


Хитрый пример... Вижу что применяется двойная диспетчеризация чтобы для разных типов аргументов работало. Но не совсем понятно зачем сделаны отдельные виртуальные операторы:
struct IObj {
    virtual void operator = ( const& CObj1 obj ) { obj.AssignTo( this ); }
    virtual void operator = ( const& CObj3 obj ) { obj.AssignTo( this ); }
}

Как предполагается их применять?
IObj objectA = new CObj1();
IObj objectB = new CObj3();
IObj object = findIObj(/*some argumetns*/);
object->operator=(objectA); // вызовется void operator = ( const& IObj obj ), а не virtual void operator = ( const& CObj1 obj )
object->operator=(objectB); // вызовется void operator = ( const& IObj obj ), а не virtual void operator = ( const& CObj3 obj )
Так и задумано? Для чего?
Отредактировано 05.02.2018 14:36 Максим Рогожин . Предыдущая версия .
Re[3]: Бывают ли нужны virtual operator= ?
От: rg45 СССР  
Дата: 05.02.18 14:45
Оценка: +1
Здравствуйте, uzhas, Вы писали:

U>давай рабочий код и свое мнение, что здесь "бывает нужно"

U>есть какое-то преимущество перед невиртуальным operator= в соответствующем наследнике MyString : public IString ?

Преимущество простое — возможность присваивания без знания статического типа (псевдокод):


bool has_placeholder(const std::string&);

template <typename T>
std::string replace_placeholder(const std::string&, const T&)

std::vector<std::shared_ptr<IString>> v;

for (IString& entry : v | indirected)
{
  if (has_placeholder(entry.str()))
  {
    entry = replace_placeholder(entry.str(), 3.14);
  }
}
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[3]: Бывают ли нужны virtual operator= ?
От: Erop Россия  
Дата: 05.02.18 14:52
Оценка: -2
Здравствуйте, uzhas, Вы писали:

U>можешь дать что-то компилируемое? тут даже дело не в прыгающих амперсандах

Это долго писать

U>вот с чего я начал: https://ideone.com/MvnI8F

Ну можно продолжить так: https://ideone.com/x8XQgk
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: Бывают ли нужны virtual operator= ?
От: Erop Россия  
Дата: 05.02.18 14:58
Оценка:
Здравствуйте, Максим Рогожин, Вы писали:


МР>Хитрый пример... Вижу что применяется двойная диспетчеризация чтобы для разных типов аргументов работало. Но не совсем понятно зачем сделаны отдельные виртуальные операторы:


Что бы эту самую двойную д. обеспечить.
Суть в том, что по уму виртуальный оператор присваивания хорошо бы иметь в виде мультиметода. Но в С++ мультиметодов нет, а ДД есть.

Использовать как-то так:
IObj& obj1 = *new CObj1;
IObj& obj2 = *new CObj2;
IObj& obj3 = *new CObj3;

jbj2 = obj1;
obj1 = obj3;
и т. д...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: Бывают ли нужны virtual operator= ?
От: uzhas Ниоткуда  
Дата: 05.02.18 15:00
Оценка: +1
Здравствуйте, rg45, Вы писали:

R>Преимущество простое — возможность присваивания без знания статического типа (псевдокод):


разумный довод

R>for (IString& entry : v | indirected)

R>{
R> entry = replace_placeholder(entry.str(), 3.14);
R>}

я бы пропилил метод Assign. думаю, что с operator= так много граблей, что их в таких сценариях лучше не использовать
Отредактировано 05.02.2018 16:31 uzhas . Предыдущая версия .
Re[3]: Бывают ли нужны virtual operator= ?
От: Erop Россия  
Дата: 05.02.18 15:00
Оценка:
Здравствуйте, Максим Рогожин, Вы писали:


МР>Так и задумано? Для чего?


Прощелкал virtual у главного метода, по мере написания примера поменял концепцию

Поправил на более реалистичный пример исходный свой ответ.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Отредактировано 05.02.2018 15:08 Erop . Предыдущая версия .
Re[5]: Бывают ли нужны virtual operator= ?
От: Erop Россия  
Дата: 05.02.18 15:07
Оценка:
Здравствуйте, uzhas, Вы писали:

U>я бы пропилил метод Assign. думаю, что с operator= так много грабель, что их в таких сценариях лучше не использовать


Это никак не связано с его виртуальностью
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: Бывают ли нужны virtual operator= ?
От: rg45 СССР  
Дата: 05.02.18 15:07
Оценка: +2
Здравствуйте, uzhas, Вы писали:

U>я бы пропилил метод Assign. думаю, что с operator= так много грабель, что их в таких сценариях лучше не использовать


Да я и сам не сторонник использования оператора присваивания в случаях, подобных этому, и тоже продпочел бы специальную функцию. Скажу больще, я был бы рад, если бы такие операторы присваивания (по произвольному типу) вообще были бы запрещены. Но они разрешены, к сожалению, а значит, их возможность быть виртуальными вполне закономерна.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 05.02.2018 15:12 rg45 . Предыдущая версия . Еще …
Отредактировано 05.02.2018 15:11 rg45 . Предыдущая версия .
Re[6]: Бывают ли нужны virtual operator= ?
От: uzhas Ниоткуда  
Дата: 05.02.18 16:21
Оценка:
Здравствуйте, Erop, Вы писали:

E>Это никак не связано с его виртуальностью


по большей части грабли из-за наследования, да
но наследование приходится пилить из-за виртуальности, так что косвенное влияние есть =)
Re[7]: Бывают ли нужны virtual operator= ?
От: Erop Россия  
Дата: 05.02.18 21:05
Оценка:
Здравствуйте, uzhas, Вы писали:

U>по большей части грабли из-за наследования, да

U>но наследование приходится пилить из-за виртуальности, так что косвенное влияние есть =)

IMHO, выбор между именами методов operator= и assign никак ни от наследования ни от виртуальности не зависит...
Единственное что тут важно, что часть методов operator= генерируется компилятором и надо быть с ними совместимым...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Бывают ли нужны virtual operator= ?
От: Chorkov Россия  
Дата: 06.02.18 07:20
Оценка:
Здравствуйте, Максим Рогожин, Вы писали:

МР>Вопросы возникли...

МР>1. Бывают ли нужны виртуальные операторы присваивания?
  пример: реализация обобщенного объекта — эмулятора ссылки (lvalue) на элемент контейнера.
#include <iostream>
#include <memory>
#include <map>
#include <algorithm>

template< typename T >
class IObjRef;
template< typename TIndex, typename TData >
class RefMyContainer;
template< typename TIndex, typename TData >
class MyContainer;


template< typename T >
class IObjRef
{
public:
    IObjRef() {}
    virtual ~IObjRef() =0 {}
    virtual operator T () const =0;
    virtual const IObjRef& operator=( const T& ) const =0;
};

template< typename TIndex, typename TData >
class RefMyContainer;
template< typename TIndex, typename TData >
class MyContainer;



template< typename TIndex, typename TData >
class RefMyContainer : public IObjRef<TData>
{
    MyContainer<TIndex, TData>& container;
    const TIndex index;

public:
    RefMyContainer( MyContainer<TIndex, TData>& container, TIndex index)
        :container(container), index(index)
    {}
    RefMyContainer(const RefMyContainer&) = default;
    RefMyContainer(RefMyContainer&&) = default;


    operator TData () const {
        return container.get(index);
    }
    const RefMyContainer& operator=( const TData& value ) const {
        container.set(index, value);
        return *this;
    }
 };


template< typename TIndex, typename TData >
class MyContainer
{
    std::map<TIndex, TData> data;
public:

    TData get(TIndex index) { return data.at(index); }
    void set(TIndex index, TData value) { data[index]=value; }


    RefMyContainer<TIndex, TData> operator[] (TIndex index)
    {
        return RefMyContainer<TIndex, TData>( *this, index );
    }
};


Использование общего базового класса, вместо объектов-ссылок конкретных типов,
позволит, например, сократить число инстансов для алгоритмов, ценой потери
производительности.
  пример.

template<typename T>
void MySwap( T& a, T& b )
{
    T tmp=a;
    a=b;
    b=tmp;
}

template< typename T >
void MySwap(const IObjRef<T>& a, const IObjRef<T>& b)
{
    T tmp = a;
    a=(T) b;
    b=tmp;
}

int main()
{
    MyContainer<int, int> map;
    map[1]=3;
    map[2]=5;

    MySwap( map[1], map[2] );

    return 0;
}
Re: Бывают ли нужны virtual operator= ?
От: MasterZiv СССР  
Дата: 08.02.18 11:30
Оценка:
Здравствуйте, Максим Рогожин, Вы писали:

МР>Вопросы возникли...

МР>1. Бывают ли нужны виртуальные операторы присваивания?

Нет, не бывает.
Кроме этого, operator = бессмысленно делать виртуальным.

МР>2. Операторы присваивания рассчитаны только на работу с объектами на стеке, а не в динамической памяти? (Т.е. когда известны типы объектов).


Любой объект в С++ при грамотном проектировании не должен рассчитывать на то, в какой памяти он хранится.
Т.е. он должен работать одинаково независимо от того, к какому классу памяти принадлежит объект.
Такова объектная модель языка С++.
Из этого правила есть исключения, но процентов на 80% именно так должно быть.

Я не очень понял вопрос, но отвечая на него, надо сказать, нет, операторы присваивания не рассчитаны только на работу с объектами на стеке.
Re[2]: Бывают ли нужны virtual operator= ?
От: Максим Рогожин Россия  
Дата: 09.02.18 13:31
Оценка:
Здравствуйте, MasterZiv, Вы писали:

МР>>1. Бывают ли нужны виртуальные операторы присваивания?


MZ>Нет, не бывает.

MZ>Кроме этого, operator = бессмысленно делать виртуальным.

Началось обсуждение с того что нужны, а под конец уже не нужны... так нужны или не нужны? Почему бессмысленно делать его виртуальным?

MZ>Я не очень понял вопрос, но отвечая на него, надо сказать, нет, операторы присваивания не рассчитаны только на работу с объектами на стеке.


Я имел ввиду что у объектов на стеке мы всегда точно знаем тип, а у объектов в динамической памяти мы часто тип не знаем (обращаемся по указателю на базовый класс к объекту какого-то производного типа). Для оператора присваивания это имеет какое-либо значение?
Re[3]: Бывают ли нужны virtual operator= ?
От: rg45 СССР  
Дата: 09.02.18 14:28
Оценка:
Здравствуйте, Максим Рогожин, Вы писали:

МР>Началось обсуждение с того что нужны, а под конец уже не нужны... так нужны или не нужны? Почему бессмысленно делать его виртуальным?


Тут важно важно понимать, что операторы присваивания бывают разные. Копирующие и перемещающие операторы присваивания — это специальные функции, которые по умолчанию генерируются компилятором и имеют достаточно жесткую логическую привязку к целевому типу. Поэтому виртуальный копипирующий или перемещающий оператор присваивания — это нечто из области экзотики.

Но есть же и другие операторы присваивания — не копирующие и не перемещающие — которые в правой части принимают тип, отличный от целевого. Такие операторы, в принципе, ни чем не отличаются от обычных функций и, как правило, без труда могут быть заменены на обычные функции. Что лучше в таких случаях, оператор присваивания или специальная функция (assign) — это всего лишь вопрос стиля. Спорить об этом — это примерно то же, что спорить о цвете обоев или о вкусе фломастеров. Я уже высказывался, я был бы рад если бы некопирующие и неперемещающие операторы присваивания были бы запрещены вовсе, тогда и вопросов бы не возникало. Но разу уж они разрешены, то запрещать им быть виртуальными причин нет о слова вообще.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[4]: Бывают ли нужны virtual operator= ?
От: Максим Рогожин Россия  
Дата: 11.02.18 09:21
Оценка:
Здравствуйте, rg45, Вы писали:

R>Копирующие и перемещающие операторы присваивания — это специальные функции, которые по умолчанию генерируются компилятором и имеют достаточно жесткую логическую привязку к целевому типу. Поэтому виртуальный копипирующий или перемещающий оператор присваивания — это нечто из области экзотики.


Почему из области экзотики? Например вот такое использование:
class Base;

Base* a = createObj(/*params*/); // возвращает объект производного класса
Base* b = createObj(/*other params*/); // возвращает объект производного класса
if (/*some condition*/) 
   a->operator=(b); //нужна виртуальность
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.