Вопросы возникли...
1. Бывают ли нужны виртуальные операторы присваивания?
2. Операторы присваивания рассчитаны только на работу с объектами на стеке, а не в динамической памяти? (Т.е. когда известны типы объектов).
Здравствуйте, Максим Рогожин, Вы писали:
МР>Вопросы возникли... МР>1. Бывают ли нужны виртуальные операторы присваивания? МР>2. Операторы присваивания рассчитаны только на работу с объектами на стеке, а не в динамической памяти? (Т.е. когда известны типы объектов).
Ну коль скоро операторы присваивания можно определять для выражений совершенно произвольных типоа, отличных от целевого, то вполне закономерно, что такие операторы могут быть виртуальными. Например, абстрактный базовый класс IString вполне мог бы иметь виртуальный оператор присваивания по обычной строке const char*.
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, Максим Рогожин, Вы писали:
МР>1. Бывают ли нужны виртуальные операторы присваивания?
Почему нет? Например может быть оператор присваивания от ОДНОГО И ТОГО ЖЕ объекта.
МР>2. Операторы присваивания рассчитаны только на работу с объектами на стеке, а не в динамической памяти? (Т.е. когда известны типы объектов).
Почему? Внутри оператора присваивания MDT всегда же известен.
Например, представь себе, что у нас есть какая-то система типов, в которых может быть общий путь преобразования, а могут быть какие-то хитрые, оптимизированные.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, rg45, Вы писали:
R>Например, абстрактный базовый класс IString вполне мог бы иметь виртуальный оператор присваивания по обычной строке const char*.
давай рабочий код и свое мнение, что здесь "бывает нужно"
есть какое-то преимущество перед невиртуальным operator= в соответствующем наследнике MyString : public IString ?
Хитрый пример... Вижу что применяется двойная диспетчеризация чтобы для разных типов аргументов работало. Но не совсем понятно зачем сделаны отдельные виртуальные операторы:
Здравствуйте, 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);
}
}
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, uzhas, Вы писали:
U>можешь дать что-то компилируемое? тут даже дело не в прыгающих амперсандах
Это долго писать
U>вот с чего я начал: https://ideone.com/MvnI8F
Ну можно продолжить так: https://ideone.com/x8XQgk
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
МР>Хитрый пример... Вижу что применяется двойная диспетчеризация чтобы для разных типов аргументов работало. Но не совсем понятно зачем сделаны отдельные виртуальные операторы:
Что бы эту самую двойную д. обеспечить.
Суть в том, что по уму виртуальный оператор присваивания хорошо бы иметь в виде мультиметода. Но в С++ мультиметодов нет, а ДД есть.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Прощелкал virtual у главного метода, по мере написания примера поменял концепцию
Поправил на более реалистичный пример исходный свой ответ.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, uzhas, Вы писали:
U>я бы пропилил метод Assign. думаю, что с operator= так много грабель, что их в таких сценариях лучше не использовать
Это никак не связано с его виртуальностью
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, uzhas, Вы писали:
U>я бы пропилил метод Assign. думаю, что с operator= так много грабель, что их в таких сценариях лучше не использовать
Да я и сам не сторонник использования оператора присваивания в случаях, подобных этому, и тоже продпочел бы специальную функцию. Скажу больще, я был бы рад, если бы такие операторы присваивания (по произвольному типу) вообще были бы запрещены. Но они разрешены, к сожалению, а значит, их возможность быть виртуальными вполне закономерна.
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, uzhas, Вы писали:
U>по большей части грабли из-за наследования, да U>но наследование приходится пилить из-за виртуальности, так что косвенное влияние есть =)
IMHO, выбор между именами методов operator= и assign никак ни от наследования ни от виртуальности не зависит...
Единственное что тут важно, что часть методов operator= генерируется компилятором и надо быть с ними совместимым...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Использование общего базового класса, вместо объектов-ссылок конкретных типов,
позволит, например, сократить число инстансов для алгоритмов, ценой потери
производительности.
пример.
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;
}
Здравствуйте, Максим Рогожин, Вы писали:
МР>Вопросы возникли... МР>1. Бывают ли нужны виртуальные операторы присваивания?
Нет, не бывает.
Кроме этого, operator = бессмысленно делать виртуальным.
МР>2. Операторы присваивания рассчитаны только на работу с объектами на стеке, а не в динамической памяти? (Т.е. когда известны типы объектов).
Любой объект в С++ при грамотном проектировании не должен рассчитывать на то, в какой памяти он хранится.
Т.е. он должен работать одинаково независимо от того, к какому классу памяти принадлежит объект.
Такова объектная модель языка С++.
Из этого правила есть исключения, но процентов на 80% именно так должно быть.
Я не очень понял вопрос, но отвечая на него, надо сказать, нет, операторы присваивания не рассчитаны только на работу с объектами на стеке.
Здравствуйте, MasterZiv, Вы писали:
МР>>1. Бывают ли нужны виртуальные операторы присваивания?
MZ>Нет, не бывает. MZ>Кроме этого, operator = бессмысленно делать виртуальным.
Началось обсуждение с того что нужны, а под конец уже не нужны... так нужны или не нужны? Почему бессмысленно делать его виртуальным?
MZ>Я не очень понял вопрос, но отвечая на него, надо сказать, нет, операторы присваивания не рассчитаны только на работу с объектами на стеке.
Я имел ввиду что у объектов на стеке мы всегда точно знаем тип, а у объектов в динамической памяти мы часто тип не знаем (обращаемся по указателю на базовый класс к объекту какого-то производного типа). Для оператора присваивания это имеет какое-либо значение?
Здравствуйте, Максим Рогожин, Вы писали:
МР>Началось обсуждение с того что нужны, а под конец уже не нужны... так нужны или не нужны? Почему бессмысленно делать его виртуальным?
Тут важно важно понимать, что операторы присваивания бывают разные. Копирующие и перемещающие операторы присваивания — это специальные функции, которые по умолчанию генерируются компилятором и имеют достаточно жесткую логическую привязку к целевому типу. Поэтому виртуальный копипирующий или перемещающий оператор присваивания — это нечто из области экзотики.
Но есть же и другие операторы присваивания — не копирующие и не перемещающие — которые в правой части принимают тип, отличный от целевого. Такие операторы, в принципе, ни чем не отличаются от обычных функций и, как правило, без труда могут быть заменены на обычные функции. Что лучше в таких случаях, оператор присваивания или специальная функция (assign) — это всего лишь вопрос стиля. Спорить об этом — это примерно то же, что спорить о цвете обоев или о вкусе фломастеров. Я уже высказывался, я был бы рад если бы некопирующие и неперемещающие операторы присваивания были бы запрещены вовсе, тогда и вопросов бы не возникало. Но разу уж они разрешены, то запрещать им быть виртуальными причин нет о слова вообще.
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, rg45, Вы писали:
R>Копирующие и перемещающие операторы присваивания — это специальные функции, которые по умолчанию генерируются компилятором и имеют достаточно жесткую логическую привязку к целевому типу. Поэтому виртуальный копипирующий или перемещающий оператор присваивания — это нечто из области экзотики.
Почему из области экзотики? Например вот такое использование:
class Base;
Base* a = createObj(/*params*/); // возвращает объект производного класса
Base* b = createObj(/*other params*/); // возвращает объект производного классаif (/*some condition*/)
a->operator=(b); //нужна виртуальность