Давно мучался таким вопросом и вот недавно опять приперло:
Уже давно существует перегрузка методов класса по количеству и типу параметров, но почему нельзя делать перегрузку по типу возращаемого значения? Это сложно реализовать или просто не надо никому? Или это может создать проблемы?
Зачем мне это понадобилось? Приведу такой пример:
// Класс возращаемого значения для BaseClassclass BaseRetVal
{
int Val1 { get {...} set {...}}
}
// Класс возращаемого значения для ChildClass
// Расширяет функциональность BaseRetVal для ChildClassclass ChildRetVal: BaseRetVal
{
int Val2 { get {...} set {...}}
}
class BaseClass
{
private BaseRetVal _m_val;
public virtual BaseRetVal SomeFunc()
{
...
return _m_val;
}
}
// Расширяет функциональность BaseClassclass ChildClass: BaseClass
{
private ChildRetVal _m_val;
public override ChildRetVal SomeFunc()
{
...
return _m_val;
}
}
Хочеться, что бы при вызове ChildClass.SomeFunc возращался тип ChildRetVal.
Возможно, я чего-то недопонимаю и этого можно добиться другими методами — советы принимаются с благодарностью
Я так и думал что такое спросят
В таком случае спросить у программиста что именно он хочет (я имею в виду компилятор)
Немного уточню: возможно ли такая перегрузка для иерархии классов, т.е. :
// Класс возращаемого значения для BaseClassclass BaseRetVal
{
int Val1 { get {...} set {...}}
}
// Класс возращаемого значения для ChildClass
// Расширяет функциональность BaseRetVal для ChildClassclass ChildRetVal: BaseRetVal
{
int Val2 { get {...} set {...}}
}
class BaseClass
{
private BaseRetVal _m_val;
public virtual BaseRetVal SomeFunc()
{
...
return _m_val;
}
public virtual void Process(BaseRetVal val)
{
...
}
}
// Расширяет функциональность BaseClassclass ChildClass: BaseClass
{
private ChildRetVal _m_val;
public override ChildRetVal SomeFunc()
{
...
return _m_val;
}
public override void Process(ChildRetVal val)
{
...
}
...
ChildClass tmp = new ChildClass();
tmp.Process(tmp.SomeFunc());
// вместо tmp.Process((ChildRetVal)tmp.SomeFunc());
// а при попытке выполнить tmp.Process(new BaseRetVal) выдавалось бы предупреждение (или ошибка)
}
Здравствуйте, LIS, Вы писали:
LIS>Возможно, я чего-то недопонимаю и этого можно добиться другими методами — советы принимаются с благодарностью
конечно недопонимаешь. есть приведение типов, которое конфликтует с тем что ты хочешь (в теории а не твоем примере). а для твоего случая нужно выходной параметр передавать последним в вызовах метода (а сам метод возвращает значение из списка стандартных) — соответсвенно сможешь перегрузить все как тебе удобно
это паралельная идеология (которая в коме кстати применяется) — методы возвращают значения из определенного списка, а под реальный результат используется последний параметр метода
Здравствуйте, IPv6, Вы писали:
IP>Здравствуйте, LIS, Вы писали:
LIS>>Возможно, я чего-то недопонимаю и этого можно добиться другими методами — советы принимаются с благодарностью IP>конечно недопонимаешь. есть приведение типов, которое конфликтует с тем что ты хочешь (в теории а не твоем примере). а для твоего случая нужно выходной параметр передавать последним в вызовах метода (а сам метод возвращает значение из списка стандартных) — соответсвенно сможешь перегрузить все как тебе удобно IP>это паралельная идеология (которая в коме кстати применяется) — методы возвращают значения из определенного списка, а под реальный результат используется последний параметр метода
А можно просвятить в чем мой пример конфликтует с теорией приведения типов?
Вот здесь
я уточнил что именно я имею в виду.
Если я могу передать в функцию, принимающую параметр типа BaseClassPar параметр типа ChildOfBaseClassPar без лишних движений, то почему я также не могу и возвращать параметры? Ведь с ChildOfBaseClassPar можно делать все, что можно делать с BaseClassPar!
Про передачу выходного параметра я тоже думал — это вариант (возможно так и сделаю), но хотелось бы элегантнее
Здравствуйте, LIS, Вы писали:
LIS>Уже давно существует перегрузка методов класса по количеству и типу параметров, но почему нельзя делать перегрузку по типу возращаемого значения? Это сложно реализовать или просто не надо никому? Или это может создать проблемы?
AFAIR доктор Страуструп в соответствующей главе "Бибилии Партии" очень подробно и понятно отвечает на Ваш вопрос.
[ posted via RSDN@Home 1.1.4 beta 3 r241, accompanied by Metallica — Master Of Puppets ]
Платформа (.NET) поддерживает перегрузку по возвращаемому значению. Проблема в том что в синтаксисе большинства языков возможны ситуации когда невозможно определить тип значения, которое функция должна вернуть.
LIS,
> Уже давно существует перегрузка методов класса по количеству и типу параметров, но почему нельзя делать перегрузку по типу возращаемого значения?
Можно. Давно есть в Ada. При желании можно эмулировать в C++ с помощью возвращения прокси-объекта с операциями приведения к соответствующим типам. Как с этим обстоит в C# —
Posted via RSDN NNTP Server 1.9 delta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>Влад, это реализуется не сложнее, чем в C++ выбор из перегруженных функций по типу, стоящему в левой части:
Это сложно реализовать в рамках выбранной граматики языка. Конфликты граматики и неопределенности тоже сложности.
Авторы языков не решают нужно или нет. Они понимают, что нужно. Просто сравнивая бенефит с проблемами принимают выбор в пользу меньших проблем.
... << RSDN@Home 1.1.4 beta 3 rev. 207>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Павел Кузнецов, Вы писали:
>> Уже давно существует перегрузка методов класса по количеству и типу параметров, но почему нельзя делать перегрузку по типу возращаемого значения?
ПК>Можно. Давно есть в Ada. При желании можно эмулировать в C++ с помощью возвращения прокси-объекта с операциями приведения к соответствующим типам. Как с этим обстоит в C# —
С++ без всяких проксей
class BaseResult {...};
class DerivedResult : public BaseResult {...};
class BaseFactory
{
public:
virtual BaseResult* foo() {...}
};
class DerivedFactory : public BaseFactory
{
public:
virtual DerivedResult* foo() {...}
};
LIS:
> Уже давно существует перегрузка методов класса по количеству и типу параметров, но почему нельзя делать перегрузку по типу возращаемого значения? Это сложно реализовать или просто не надо никому? Или это может создать проблемы? > > Зачем мне это понадобилось? Приведу такой пример:
[]
Если я правильно понял, на самом деле тебе хочется не перегрузки по типу возвращаемого значения, а возвращения ковариантного (covariant) типа.
В С++ это реализовано. Фича удобная, в плюсах проблем не создает (кроме переносимости — не поддерживается древними компиляторами).
Здравствуйте, VladD2, Вы писали:
VD>А какова по-твоему разница между перегрузкой и переопределением?
Ну, у меня возникло подозрение, что LIS спросил про переопределение с возвращением ковариантного типа.
Если же именно про перегрузку — то тем более нет проблем (в С++).
VladD2,
> ПК> Влад, это реализуется не сложнее, чем в C++ выбор из перегруженных функций по типу, стоящему в левой части:
> Это сложно реализовать в рамках выбранной граматики языка. Конфликты граматики и неопределенности тоже сложности.
Никаких сложностей в рамках выбранной грамматики тоже нет. Вот пример, наглядно это демонстрирующий:
struct C
{
C( int );
operator int() const;
operator double() const;
};
int main()
{int i = C(10);
double d = C(5);
}
С точки зрения грамматики выделенные строки эквивалентны случаю, если бы C были бы перегруженными по результату функциями.
> Авторы языков не решают нужно или нет.
По крайней мере, в случае C++ можно легко открыть "Дизайн и эволюцию", и убедиться, что подавляющее количество подобных решений начинаются как раз с раздумий, насколько та или иная возможность считается нужной.
Posted via RSDN NNTP Server 1.9 delta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>VladD2,
>> ПК> Влад, это реализуется не сложнее, чем в C++ выбор из перегруженных функций по типу, стоящему в левой части:
>> Это сложно реализовать в рамках выбранной граматики языка. Конфликты граматики и неопределенности тоже сложности.
ПК>Никаких сложностей в рамках выбранной грамматики тоже нет. Вот пример, наглядно это демонстрирующий: ПК>
ПК>struct C
ПК>{
ПК> C( int );
ПК> operator int() const;
ПК> operator double() const;
ПК>};
ПК>int main()
ПК>{
ПК> int i = C(10);
ПК> double d = C(5);
ПК>}
ПК>
ПК>С точки зрения грамматики выделенные строки эквивалентны случаю, если бы C были бы перегруженными по результату функциями.
Я бы сказал, разрешение перегрузки выполняется после синтаксического анализа, так что грамматика тут совершенно не при чем. Всё что нужно -- чуть-чуть модифицировать блок, выбирающий среди списка перегруженных функций наиболее подходящую. Тут, правда, возникает одна проблема.
Для случая
int a=...;
double b=...;
int x=fun(a,b);
мы точно знаем желательный тип возвращаемого значения.
А вот как быть с таким примером?
int g(int);
int g(double);
int fun(int a,double b);
double fun(int a,double b);
...
int x=g(fun(a,b));
Или ещё лучше.
template <class T>
int g(T);
int fun(int a,double b);
double fun(int a,double b);
...
int x=g(fun(a,b));
Понятно, что в этих случаях разрешение перегрузки по типу возвращаемого значения невозможно, но тогда какая от неё польза? По-видимому -- минимальная.
Здравствуйте, Кодт, Вы писали:
К>Если же именно про перегрузку — то тем более нет проблем (в С++).
Речь именно о прегрузке, причем о перегрузке по типу возвращаемого значения. И тут проблемы не у С++, а у дизайнеров языка. Так как с возникающими неоднозначностями приходится бороться.
... << RSDN@Home 1.1.4 beta 3 rev. 207>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>С точки зрения грамматики выделенные строки эквивалентны случаю, если бы C были бы перегруженными по результату функциями.
Здравствуйте, Шахтер, Вы писали:
Ш>Понятно, что в этих случаях разрешение перегрузки по типу возвращаемого значения невозможно,
+1
Ш> но тогда какая от неё польза? По-видимому -- минимальная.
Чесно говоря хотелось бы поиметь ее в более простых случаях.
Например мне не очень нравятся конструкции вроде:
TypeOfResult result = (TypeOfResult)Query("некоторый запрос");
Было бы здорово если можно было перегрузить Query по возвращаемому значению. Тогда в него можно было встроить понятное объяснение произошедшей ошибки или еще чего. Ну, и синтаксис стал бы проще.
... << RSDN@Home 1.1.4 beta 3 rev. 207>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.