Функция полиморфизма C++, принимающая void * и другой тип указателя в качестве аргумента: считается ли она неоднозначной?
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-й формы. Будет ли вызов с указателем производного класса в качестве аргумента выполнять первую или вторую форму? т.е. будет ли приведен указатель производного класса к базовому указателю абстрактного класса (и, следовательно, будет действовать 2-я форма), или он будет приведен к void *
(и, таким образом, первая форма будет в действии) перед вызовом bar()
?
1 ответ
Согласно правилам разрешения перегрузки (раздел Ранжирование последовательностей неявного преобразования), поскольку аргумент может быть преобразован в тип параметра любой функции, в этом случае наилучшей жизнеспособной будет функция, для которой неявное преобразование лучше.
За:
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);
,
Смотрите здесь пример последнего.