Страница 1 из 3
Каким образом выбирается версия функции, принимающей указатель на полиморфный класс?
Добавлено: 06 янв 2016, 11:19
Сионист
Код: Выделить всё
class A
{
public:
virtual void m()=0;
};
class B : public A
{
public:
virtual void m()
{
}
};
class D : public B
{
public:
virtual void m()
{
}
};
class C : public A
{
public:
virtual void m()
{
}
};
class E : public C
{
public:
virtual void m()
{
}
};
void f(A *a)
{
}
void f(B *b)
{
}
void f(C *c)
{
}
int main ()
{
A *p;
p=new B;
f(p);
delete p;
p=new C;
f(p);
delete p;
p=new D;
f(p);
delete p;
p=new E;
f(p);
delete p;
return 0;
}
Каким образом здесь выбирается версия функции в каждом случае вызова?
Re: Каким образом выбирается версия функции, принимающей указатель на полиморфный кла
Добавлено: 06 янв 2016, 13:58
Romeo
Я три раза перечитал твой пост, поправил там кучу опечаток в коде и самом топике, и, в конце-концов, пришёл к выводу, что тебя расстраивает тишина на форуме, и ты подобными темами просто пытаешься расшевелить людей, ответ же на вопрос тебе совсем не интересует. По другому я не могу объяснить такую кучу опечаток. Это просто наплевательское отношение к читателям. Неужели трудно хотя бы один раз перечитать то, что запостил? Или это сделано намеренно, и это такой грубый троллинг?
По теме: в данном случае функция будет выбрана по наибольшему соответствию типа. Иными словами, во всех случаях будет вызвана f(A*).
А в чём смысл таких функций, если полиморфизм будет работать благодаря виртуальным методам? Как раз одной функции достаточно.
Re: Каким образом выбирается версия функции, принимающей указатель на полиморфный кла
Добавлено: 06 янв 2016, 14:46
Сионист
Компилятор ни одной очепятки не заметил.
По теме: в данном случае функция будет выбрана по по наибольшему соответствию типа. Иными словами, во всех случаях будет вызвана f(A*).
Страуструп прямо пишет, что выбирается функция, максимально соответствующая фактическому типу. Если есть версия, принимающая фактический тип, то вызывается она, иначе - версия, принимающая указатель на ближайшего предка. В данном случае
Код: Выделить всё
class A
{
public:
virtual void m()=0;
};
class B : public A
{
public:
virtual void m()
{
}
};
class D : public B
{
public:
virtual void m()
{
}
};
class E : public C
{
public:
virtual void m()
{
}
};
void f(A *a)
{
}
void f(B *b)
{
}
void f(C *c)
{
}
int main ()
{
A *p;
p=new B;
f(p); //Вызывается версия, принимающая B*
delete p;
p=new C;
f(p); //Вызывается версия, принимающая C*
delete p;
p=new D;
f(p); //Вызывается версия, принимающая B*
delete p;
p=new E;
f(p); //Вызывается версия, принимающая C*
delete p;
return 0;
}
. А вот каким образом это делается? Если
Код: Выделить всё
class A
{
public:
virtual void m()=0;
};
class B : public A
{
public:
virtual void m()
{
}
};
class D : public B
{
public:
virtual void m()
{
}
};
class E : public C
{
public:
virtual void m()
{
}
};
void f(B b)
{
}
void f(C c)
{
}
int main ()
{
B b;
C c;
D d;
E e;
f(b);
f(c);
f(d);
f(e);
return 0;
}
, то фактический тип известен на этапе компиляции. А в случае указателя?
Re: Каким образом выбирается версия функции, принимающей указатель на полиморфный кла
Добавлено: 06 янв 2016, 14:51
Romeo
Вместо public там было везде написано publuc. Вместо virtual - firtual. Интересно, как это компилилось. Может компилятор специальный?

Re: Каким образом выбирается версия функции, принимающей указатель на полиморфный кла
Добавлено: 06 янв 2016, 14:53
Absurd
пришёл к выводу, что тебя расстраивает тишина на форуме, и ты подобными темами просто пытаешься расшевелить людей, ответ же на вопрос тебе совсем не интересует.
Ну не знаю, если погуглить "taras atavin", можно много чего интересного найти.
Re: Каким образом выбирается версия функции, принимающей указатель на полиморфный кла
Добавлено: 06 янв 2016, 15:00
Romeo
Absurd писал(а):Ну не знаю, если погуглить "taras atavin", можно много чего интересного найти.
Первая же ссылка ведёт на некий форумный профиль с такой же авой, как и у нашего друга. Это что, один и тот же человек?

Re: Каким образом выбирается версия функции, принимающей указатель на полиморфный кла
Добавлено: 06 янв 2016, 15:03
Сионист
А в чём смысл таких функций, если полиморфизм будет работать благодаря виртуальным методам? Как раз одной функции достаточно.
А ни кто не говорил, что эти функции вообще будут обращаться к методам. Может они обращаются только к переменным-членам?
Код: Выделить всё
class A
{
public:
virtual void m()=0;
};
class B : public A
{
public:
int x;
virtual void m()
{
}
};
class C : public A
{
public:
double y;
virtual void m()
{
}
};
class D : public B
{
public:
char c;
virtual void m()
{
}
};
class E : public C
{
public:
bool f
virtual void m()
{
}
};
void f(A *a)
{
}
void f(B *b)
{
x=2;
if (dynamic_cast<D*>b)
{
(dynamic_cast<B*>a)->с='f';
}
}
void f(C *c)
{
y*=2.4;
if (dynamic_cast<D*>b)
{
(dynamic_cast<B*>a)->f=!(dynamic_cast<B*>a)->f;
}
}
int main ()
{
A *p;
p=new B;
f(p);
delete p;
p=new C;
f(p);
delete p;
p=new D;
f(p);
delete p;
p=new E;
f(p);
delete p;
return 0;
}
.
Вместо public там было везде написано publuc. Вместо virtual - firtual. Интересно, как это компилилось. Может компилятор специальный?
А куда при исправлении делся класс C?
Re: Каким образом выбирается версия функции, принимающей указатель на полиморфный кла
Добавлено: 06 янв 2016, 15:09
Absurd
Первая же ссылка ведёт на некий форумный профиль с такой же авой, как и у нашего друга.
Я случайно напоролся на этот профиль когда значение "Эй Си" искал.
Re: Каким образом выбирается версия функции, принимающей указатель на полиморфный кла
Добавлено: 06 янв 2016, 16:21
Romeo
Сионист, так код не пишут: касты не для этого созданы.
По поводу указателя - я уже сказал, как всё будет работать. Всегда будет вызываться f(A*), так как ты сам делаешь кастинг к указателю этого типа при присваивании.
Re: Каким образом выбирается версия функции, принимающей указатель на полиморфный кла
Добавлено: 06 янв 2016, 16:33
Сионист
Объекты могут поставляться сторонним кодом, при этом может отсутствовать возможность переписать методы, но могут требоваться различные действия в зависимости от фактического класса каждого объекта. Предположим, под A скрывается TEvent, версии функции - это обработчики, а метод вызывается в том случае, если приложение обрабатывает данное событие. Факт наличия версии, принимающей указатель на фактический класс, - не достаточный признак. Пусть
Код: Выделить всё
TEvent
{
private:
volatile bool f;
public :
virtaual void Processed()=0;
};
class TCharEvent: public TEvent
{
};
class TUnichar32Event: public TCharEvent
{
public:
public:
virtaual void Processed()
{
f=true;
}
chart32_t Code;
};
class TUnichar16Event: public TCharEvent
{
public:
public:
virtaual void Processed()
{
f=true;
}
union
{
wchar_t Code;
wchar_t SurrogatCode[2];
};
};
class TAnsicharEvent: public TCharEvent
{
public:
public:
virtaual void Processed()
{
f=true;
}
char Code;
};
class TLButtonEvent: public TEvent
{
public:
public:
virtaual void Processed()
{
f=true;
}
int x;
int y;
};
и по каким то причинам решено TUncar32Event и TAnsicharEvent обрабатывать в одном обработчике, принимающем указатель на TCharEvent, TLButttonEvent - в другой, а TUnichar16Event - не обрабатывать вообще. Хорошо, когда вызываемый и вызывающий код прописаны в одном проекте, тогда просто используем указатель в качестве фактического параметра и ни каких гвоздёв. А если они в разных проектах? Если я передам один указатель на функцию, то он будет указывать только на одну версию и тест показывает, что по указателю на функцию вызывается та версия, на которую он указывает, всегда одна и та же. Тот же тест показывает, что при вызове функции по имени самой функции стандарт соблюдается и вызываемая версия зависит от фактического класса объекта, на которую указывает параметр. А как это достигается? Может отсюда можно вытянуть способ выбора версии в стороннем вызывающем коде?