Приветствую, господа, и, дамы, если есть, конечно тоже.
Попробовал поискать здесь и в инете, но безуспешно. Если коротко, пример:
class P1 {};
class P2 {};
class A
{
public:
void f( P1* );
};
class B
{
public:
void f( P2* );
};
class C :
public A,
public B
{
public:
C()
{
P2* p;
f( p );
}
};
int main()
{
C q;
}
на что например ICL (уверен, что справедливо) отвечает:
test1.cpp
test1.cpp(18): error: "С::f" is ambiguous
f( p );
^
Почему не разрешена такая перегрузка, с точки зрения компилятора — все однозначно. Можно просто указать пункт стандарта в котором описана данная ситуация, я не нашел.
В моей ситуции указывать явно имя базового класса при вызове f() нельзя, (хотя бы потому что оно очень длинное, это шаблон). Хочется найти элегантное решение.
class P1 {};
class P2 {};
class Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
{
public:
void f( P1* );
};
class Bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
{
public:
void f( P2* ) {};
};
typedef Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa A;
typedef Bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb B;
class C :
public A,
public B
{
public:
C()
{
P2* p;
B::f( p );
}
};
int main()
{
C q;
}
Исправлена раскраска — WH
Правильно работающая программа — просто частный случай Undefined Behavior
Здравствуйте, Maxim Lock, Вы писали:
ML>Замечательно, но почему typedef такие чудеса сотворил?! Почему без него перегрузка корректно не разрешается?
Удалено избыточное цитирование — WH
..По-моему ,ничего здесь typedef не сотворил .B:: сотворил.Судя по всему классы A(Aaaaaaaaaaaaaaa) и B (Bbbbbbbbbbbb) схожи по структуре(указатель на один можно легко переопределить в указатель на другой) и ..естессно компилятор не решается вызвать тот или иной метод f().
В книге Б. Страуструпа описана такая ситуация,как одна из встречающихся ошибок...
V>..По-моему ,ничего здесь typedef не сотворил .B:: сотворил.Судя по всему классы A(Aaaaaaaaaaaaaaa) и B (Bbbbbbbbbbbb) схожи по структуре(указатель на один можно легко переопределить в указатель на другой) и ..естессно компилятор не решается вызвать тот или иной метод f(). V>В книге Б. Страуструпа описана такая ситуация,как одна из встречающихся ошибок
Да, нехорошо так издеваться, спасибо, что сказал, а я добавленный B:: перед f не заметил, подумал что это typedef колдовство
К сожалению, нельзя использовать явное указание базового класса в моем случае. Все очень просто на самом деле, хочется чтобы в классе унаследованном от одного/двух/.../n разных специализаций шаблона, можно было использовать вызовы метода из одного из базового класса, с одинаковым именем, но сторогим соответствием типа аргумента. Обычная перегрузка это позволяет, так в чем разница, (методы не виртуальные).
Так вопрос в силе! ну скажите, в чем проблема почему так нельзя перегрузить методы через базовые класы?! Или как это можно красиво обойти, "обертки" какие-то может сделать ...
ML>Да, нехорошо так издеваться, спасибо, что сказал, а я добавленный B:: перед f не заметил, подумал что это typedef колдовство
ML>К сожалению, нельзя использовать явное указание базового класса в моем случае. Все очень просто на самом деле, хочется чтобы в классе унаследованном от одного/двух/.../n разных специализаций шаблона, можно было использовать вызовы метода из одного из базового класса, с одинаковым именем, но сторогим соответствием типа аргумента. Обычная перегрузка это позволяет, так в чем разница, (методы не виртуальные).
ML>Так вопрос в силе! ну скажите, в чем проблема почему так нельзя перегрузить методы через базовые класы?! Или как это можно красиво обойти, "обертки" какие-то может сделать ...
Действительно, это запрещено стандартом. Для обяснения читай Страуструпа.
А обойти это можно только явно указав использование обоих имён в области видимости класса:
class C : public A, public B {
using A::f;using B::f;
C() {
P2* p = 0;
f(p);
}
};
Или написать промежуточный классик:
class Immediate : public A, public B {
using A::f;using B::f;
};
class C : publicImmediate {
C() {
P2* p = 0;
f(p);
}
};
Который можно сделать шаблонным спомощью списков типов.
T>Действительно, это запрещено стандартом. Для обяснения читай Страуструпа. T>А обойти это можно только явно указав использование обоих имён в области видимости класса:
Удалено избыточное цитирование — WH
T>Который можно сделать шаблонным спомощью списков типов.
Спасибо, интересный вариант, но опять к сожалению нужно указывать явно базовый класс, и список типов я под vc6 использовать не смогу (я знаю про порт Loki для vc6 by Rani Sharoni, но мы его не используем), да и он помог бы лишь отчасти.
Я хочу попробовать вариант с шаблонной базовой функцией, которая по типу аргумента все же "перенаправляет" явно вызов у нужному родительскому классу, что-то вроде статического patterna'а visitor, если интересно — расскажу, что получилось (но пока не получилось )
Re: Перегрузка метода при множественном наследовании.
От:
Аноним
Дата:
14.03.04 17:03
Оценка:
Если ты хочешь ссылку на стандарт, читаи clause 10, 3.
До того, как сработает разрешение перегрузки, происходит поиск имен. Имя f — неоднозначно.
Re: Перегрузка метода при множественном наследовании.
От:
Аноним
Дата:
15.03.04 12:50
Оценка:
Здравствуйте, Maxim Lock, Вы писали:
ML>Почему не разрешена такая перегрузка, с точки зрения компилятора — все однозначно. Можно просто указать пункт стандарта в котором описана данная ситуация, я не нашел.
ML>В моей ситуции указывать явно имя базового класса при вызове f() нельзя, (хотя бы потому что оно очень длинное, это шаблон). Хочется найти элегантное решение.
Насколько я помню, разрешение имен в этом случае идет буз ечета аргументов. Поэтому необходимо четко указывать базовый класс или использовыать using.
Re[2]: Перегрузка метода при множественном наследовании.
Здравствуйте, Аноним, Вы писали:
А>Если ты хочешь ссылку на стандарт, читаи clause 10, 3. А>До того, как сработает разрешение перегрузки, происходит поиск имен. Имя f — неоднозначно.
Спасибо, вы правы.
Re[2]: Перегрузка метода при множественном наследовании.
Здравствуйте, Аноним, Вы писали:
А>Насколько я помню, разрешение имен в этом случае идет буз ечета аргументов. Поэтому необходимо четко указывать базовый класс или использовыать using.