Функция полиморфизма 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);,

Смотрите здесь пример последнего.

Другие вопросы по тегам