C ++ полиморфизм функций, принимающих void *
и другой тип указателя в качестве аргументов: считается ли он неоднозначным?
Я обеспокоен тем, что любой указатель может быть приведен к void*
, будет ли выполняться второй вызов бара ниже void bar(void*)
вместо моего ожидаемого void bar(int*)
в программе ниже?
Я протестировал на своем g ++, и он работает как положено (то есть int * не будет приведен к void *). Но может ли кто-нибудь прокомментировать / ответить на этот вопрос в отношении спецификаций языка C ++?
foo.h:
class Foo {
public:
void bar(void *);
void bar(int *);
};
main.cpp:
...
struct A *p1;
int *p2;
Foo foo;
...
foo.bar(p1);
foo.bar(p2);
Кроме того, скажем, bar
В настоящее время виртуальные функции полиморфизма, принимая void*
аргумент в качестве 1-й формы, и указатель на базовый абстрактный класс в качестве 2-й формы. Будет ли вызов с указателем производного класса в качестве аргумента выполнять первую или вторую форму? будет ли приведен указатель производного класса к его базовому указателю абстрактного класса (и, таким образом, будет действовать вторая форма), или он будет приведен к void *
(и, таким образом, первая форма будет в действии) перед вызовом bar()
?
В соответствии с правила разрешения перегрузки (раздел Ранжирование неявных конверсионных последовательностей), поскольку аргумент может быть преобразован в тип параметра любой функции, лучшей жизнеспособной функцией в этом случае будет та, у которой неявное преобразование лучше.
За:
class Foo {
public:
void bar(void*);
void bar(int*);
};
// ...
Foo foo;
int* p2;
foo.bar(p2);
Первый ранг 3 (преобразование), а второй — ранг 1 (Полное совпадение). Поскольку точное совпадение, которое не требует преобразования, лучше, чем преобразование, оно вызовет void bar(int*)
,
Это становится более сложным во втором случае:
class Foo {
public:
virtual void bar(void*);
virtual void bar(Foo*);
virtual ~Foo() = default;
};
class FooTwo : public Foo {};
// ...
Foo foo;
FooTwo footwo;
foo.bar(&footwo);
Поскольку оба ранга 3 (преобразование), это затем следует правилам рейтинга конверсии. И поскольку обе конверсии имеют одинаковый ранг конверсии, это затем распространяется на расширенные правила ранжирования конверсий. Расширенное правило 2 гласит:
Преобразование, которое преобразует указатель-в-производное в указатель-на-основание, лучше, чем преобразование указатель-в-производное в указатель-на-пустоту, а преобразование указатель-на-основание в void лучше, чем указатель на производное аннулировать
Учитывая это, void bar(Foo*)
считается лучшим совпадением, чем void bar(void*)
Это означает, что он будет выбран foo.bar(&footwo);
,
Увидеть Вот для примера последнего.
Других решений пока нет …