Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > C/C++: Общие вопросы > Перегрузка =, ->, (), [] |
Автор: 0x07L 15.6.2006, 19:24 |
сабж |
Автор: skyboy 15.6.2006, 19:28 |
а функциями разве нельзя? или как надо? |
Автор: Earnest 15.6.2006, 20:03 |
Наверное, имеется в виду, почему нельзя перегрузить глобальными функциями... Добавлено @ 20:12 Пыталась представить себе глобальную перегрузку оператора, скажем ()... Стандартный оператор () применим только к функциям. Значит, перегрузим мы его глобально, и вместо вызова ожидаемой функции с некоторыми типами аргументов будет вызываться... что? Другая функция? Очень полезно. Главное, наглядно. Аналогично с другими операциями: [] в стандартном виде применим только к указателям-массивам и только с целыми индексами. Перегрузили. С индексами типа complex. А что, нельзя? Какой смысл будет иметь выражение pA[c], где pA указатель, а с - complex? Ммм... наверное индексация в двумерном массиве, не иначе... Ну и так далее. Тихо приходим к выводу, что смысл этих операций должен зависеть от типа левого операнда. А раз так, то имеет смысл выразить сию идею явно: запретить глобальную перегрузку. |
Автор: MAKCim 15.6.2006, 20:59 |
потому как это может нарушить семантику использования языковых средств честно говоря даже не представляю, зачем это вообще надо (кроме разве что operator=) |
Автор: 0x07L 15.6.2006, 21:31 |
Зачем запрещать, если можно разрешить. Неужели найдутся программисты, которые захотят использовать индексы типа complex? А дополнительные возможности (даже такие сомнительные) тоже могут кому-нибудь пригодиться IMHO. |
Автор: DeadSoul 15.6.2006, 21:46 | ||
std::map. |
Автор: MAKCim 15.6.2006, 21:49 | ||
если такой логике следовать, то в язык можно много чего еще ввести стандартные операции в языке, имхо, не должны переопределяться, для этого вводится новый пользовательский тип и уже с ним можно извращаться ![]() p.s приведи хоть один пример, где перегрузка глобальных [], (), -> может пригодится? |
Автор: skyboy 15.6.2006, 22:35 |
я бы добавил ещё сравнение == Почему только это? А потому что копирование объектов ("=") может сопровождаться кучей условий и вызовом конструкторов, который не совершает "стандартная" операция копирования объектов. Почему сравнение? А чтоб упростить сравнение сложных типов - тех же списков или структур. |
Автор: Earnest 16.6.2006, 07:33 | ||
Есть такое понятие - адаптер. Пиши свой класс, и делай с ним, что хочешь. Если каждый раз, когда нам потребуется добавить какому-то классу функциональность, мы будем изменять его интерфейс, мы очень скоро придем к куче ... ммм ... Это самый тупой способ сопровождения кода. И самый опасный. Под изменением интерфейса я понимаю не только функции члены, но и любой интерфейс класса в расширенном понимании. Если же переопределять глобальный оператор не в интерфейсе класса (рядом с классом), а где-то еще - получим все прелести разного поведения в зависимости от подключенных заголовков. Как раз этот оператор можно переопределить глобально. Что, кстати, не очень здорово: можно запросто получить программу, где в одном месте объекты A сравниваются одним способом, а в другом - совершенно другим. |
Автор: skyboy 16.6.2006, 10:01 |
Earnest, знач, переопределять только в front-end модуле, только в котором мы это сравнение и будем использовать и который не будет подключаться к другим модулям(в смысле, по задумке ЕГО не будут подключать) |
Автор: Earnest 16.6.2006, 10:23 |
Это из серии "благими намерениями". Исходный код имеет тенденцию жить своей жизнью. Сначала ты переопределяешь глобальный оператор (скажем сравнения объектов A) в cpp-файле, и счастлив - быстро, удобно, работает. Потом постепенно разрастается до неприличных размеров, и надо его делить. А как же наш специальный оператор? Он уже должен использоваться в 2 файлах. Дублируем код? Выносим в заголовок? И то, и другое одинаково плохо. Причем, заметь, это может сделать совсем другой программист (а не автор первой версии кода). Или автор, но через несколько лет. Если какая-то гадость может случится, она рано или поздно обязательно случится. Причем тогда, когда об этой милой особенности уже никто не помнит. А искать такие ошибки - сплошная радость. Гораздо проще написать класс - обертку, подогнав под свои нужды. Это уж точно никогда никому не повредит. |
Автор: MAKCim 16.6.2006, 10:39 | ||||
OK
|
Автор: skyboy 16.6.2006, 10:54 |
Earnest, полностью согласен. И рад, что в жизни не переопределял операторы, ибо с С++ почти не работаю ![]() |
Автор: 0x07L 16.6.2006, 15:16 |
2_MAKCim Просто здорово. Не знал, что перегрузка запятой может быть так полезна. Хотя, если я не ошибаюсь, код можно было написать и без перегрузки запятой, пользуясь лишь "<<" (это из области "кому что больше нравится") 2_Earnest Дельное замечание. --------------------------- Сегодня меня чуть не побили за то, что я задумал перегружать дружественными функциями операторы (), [], ->. Приводили мне те же аргументы, что и Earnest в своем первом посте (левый операнд важнее правого). Таким образом, это уже не личное мнение, а позиция большинства. Так что от этих операндов я, пожалуй, отстану. А вот относительно оператора присваивания меня переубедить не смогли. Хотя... Как известно, operator=, если не переопределен, конструируется (если можно так выразиться) компилятором и осуществляет побайтовое копирование объекта. Переопределяют operator= прежде всего для того, чтобы обеспечить правильную работу указателей-членов класса. А тот, кто переопределяет operator= стандартного класса дружественной функцией для поддержки возможности присваивания объекту такого класса объекта нашего класса, не имеет доступа к этим указателям. Между тем смысл оператора присваивания в том, чтобы полностью менять левый операнд (а не прибавлять к какому-нибудь элементу объекта какое-либо значение, не делить, не умножать, не возводить в степень, ... не получать доступ к какому-либо элементу), что предполагает изменение этих указателей. Получается, вообще говоря, хрень и никому эта хрень, естественно, не нужна. Вопрос по operator= решен. Если моя версия не вызывает ни у кого сомнений, пожалуй, стоит пометить вопрос как решенный. |
Автор: UnrealMan 16.6.2006, 16:38 | ||
Чем плох вынос в заголовок такого глобального определения:
|
Автор: Earnest 16.6.2006, 17:39 |
Уточняю: плохо не вообще выносить такие определения в заголовочные файлы, а отделать их от интерфейса класса. Другими словами, если A - библиотечный класс (в файле, который ты не должен менять), а ты определяешь для него какой-нибудь глобальный оператор, для определенности ==, в другом заголовочном файле, ты создаешь возможность разного сравнения объектов A в разных модулях. Т.е. все начинает зависеть от того, включена ли твоя версия оператора или нет. Если учесть, что h-файлы имеют тенденцию вкладываться друг в друга, то в один прекрасный момент может случиться так, что добавление еще одного include с какой-нибудь нужной функциональностью, приведет к изменению сравнения объектов A. Причем сразу это можно и не заметить. Избежать эту ситуацию можно только если последовательно придерживаться принципа: весь интерфейс объекта должен быть определен там же, где и сам объект. Нужно тебе локально изменить сравнение объектов A - заверни их в класс B и реализуй новые операторы для него. Это относится ко всем общеупотребимым операторам: +, <, etc. |
Автор: UnrealMan 16.6.2006, 18:13 | ||||
Уже вижу, чем :-) С переопределением оператора != под конкретный класс (при необходимости) возникают проблемы (операторы-друзья вообще идут лесом, независимо от константности ссылок T&). Хотя в чём может заключаться эта необходимость?
Применительно к моему примеру (!= и == можно поменять местами) функциональность вряд ли будет изменена. |
Автор: DeadSoul 16.6.2006, 20:32 |
UnrealMan, тем, что ты научишься сравниваит и мои классы тоже. |
Автор: MAKCim 16.6.2006, 21:00 | ||
так неинтересно ![]() |
Автор: UnrealMan 17.6.2006, 10:45 |
Не понял. Попробуй объяснить попонятней. |
Автор: DeadSoul 17.6.2006, 11:31 | ||
После включения h-файла c твоим шаблоном operator!= будет определен для ВСЕХ классов содержащих operator!=. А ты не думаешь, что я специально не создавал оператор!=?! |
Автор: UnrealMan 17.6.2006, 12:36 |
Это ещё зачем специально его не создавать? Добавлено @ 12:37 Ты, должно быть, хотел сказать "содержащих operator=="? |
Автор: DeadSoul 17.6.2006, 13:13 | ||||
Затем же зачем конструкторы делают explicit. Чтобы компилятор сообщал мне об ошибках
Ну да |
Автор: UnrealMan 17.6.2006, 13:22 |
Т.е. оператор== создали, а != запретили. Не пойму, в чём прикол. Смысл такого запрета? Операторы не запрещают для того, чтобы компилятор выдавал ошибку (ошибка – это следствие запрета, а не причина :-) ). |
Автор: DeadSoul 17.6.2006, 14:05 | ||
В том, что мне НЕ нужен оператор != |
Автор: LPBOY 17.6.2006, 14:25 |
Где-то слышал (по крайней мере про operator= ), что запретили его глобальный аналог, потому что в этом случае возможны любые преобразования над объектом по правую сторону от него, что не очень интуитивно. |
Автор: UnrealMan 17.6.2006, 15:16 |
Ну, не используй, коли не нужен :-) Запрещать-то зачем? |
Автор: DeadSoul 18.6.2006, 16:57 | ||
Зачем, что бы при попытке использования данного оператора(который я не писал) я получил ошибку компилятора, а не непонятные глюки |
Автор: UnrealMan 18.6.2006, 18:18 | ||
Зачем тебе эта ошибка? Раз ты пытаешься использовать этот оператор, значит, он тебе уже нужен. Причём нужен именно в значении отрицания == (в противном случае это какой-то очень странный стиль программирования получается). Какие здесь могут быть глюки? |
Автор: DeadSoul 18.6.2006, 18:47 | ||||
ВОТ ЗАЧЕМ |
Автор: UnrealMan 18.6.2006, 20:52 | ||
Это ещё с какой радости? Хочешь (гарантированно) передачу по ссылке – изволь писать A &a или const A &a (если a не модифицируется и нужно оставить возможность неявных преобразований). |
Автор: DeadSoul 18.6.2006, 21:23 | ||
Я забыл\опечатался и т.д. |
Автор: 0x07L 19.6.2006, 18:08 | ||
Не, не катит. Почему же тогда не запретили operator+=? Там преобразования правого аргумента, по-моему, не более интуитивны. |
Автор: UnrealMan 19.6.2006, 22:36 |
|