Подтвердить что ты не робот

С++ перегружено предупреждение виртуальной функции clang?

clang выдает предупреждение при компиляции следующего кода:

struct Base
{
    virtual void * get(char* e);
//    virtual void * get(char* e, int index);
};

struct Derived: public Base {
    virtual void * get(char* e, int index);
};

Предупреждение:

warning: 'Derived::get' hides overloaded virtual function [-Woverloaded-virtual]

(указанное предупреждение должно быть включено, конечно).

Я не понимаю, почему. Обратите внимание, что раскомментирование одной и той же декларации в Base отключает предупреждение. Я понимаю, что поскольку две функции get() имеют разные подписи, не может быть скрытия.

Правильно ли это? Почему?

Обратите внимание, что это на MacOS X, запущенном последней версией Xcode.

clang --version
Apple LLVM version 5.0 (clang-500.1.74) (based on LLVM 3.3svn)

Обновление: такое же поведение с Xcode 4.6.3.

4b9b3361

Ответ 1

Это предупреждение предназначено для предотвращения случайного скрытия перегрузок при планировании переопределения. Рассмотрим несколько иной пример:

struct chart; // let pretend this exists
struct Base
{
    virtual void* get(char* e);
};

struct Derived: public Base {
    virtual void* get(chart* e); // typo, we wanted to override the same function
};

Как это предупреждение, это не обязательно означает, что это ошибка, но это может означать одно. Обычно такие предупреждения имеют возможность отключить их, будучи более явными и позволяя компилятору знать, что вы намеревались написать то, что вы написали. Я считаю, что в этом случае вы можете сделать следующее:

struct Derived: public Base {
    using Base::get; // tell the compiler we want both the get from Base and ours
    virtual void * get(char* e, int index);
};

Ответ 2

R. Решение Martinho Fernandes отлично действует, если вы действительно хотите, чтобы метод get() принимал один аргумент char * в область Derived.

Собственно, в предоставленном фрагменте нет необходимости в виртуальных методах (поскольку Base и Derived не используют какой-либо метод с одной и той же сигнатурой).

Предполагая, что на самом деле существует потребность в полиморфизме, поведение скрытия может, тем не менее, быть тем, что предполагается. В этом случае можно локально отключить предупреждение Clang со следующей прагмой:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Woverloaded-virtual"
    // Member declaration raising the warning.
#pragma clang diagnostic pop

Ответ 3

Предупреждение означает, что не будет  void * get (char * e) функции в классе Derived, потому что он скрыт другим методом с тем же именем. Компилятор не будет искать функцию в базовых классах, если производный класс имеет хотя бы один метод с указанным именем, даже если он имеет другие аргументы.

Этот пример кода не будет компилироваться:

class A
{
public:
    virtual void Foo() {}
};

class B : public A
{
public:
    virtual void Foo(int a) {}
};


int main()
{
    B b;
    b.Foo();
    return 0;
}

Ответ 4

Другой способ отключить предупреждение, сохраняющее открытый публичный интерфейс структуры, будет следующим:

struct Derived: public Base
{
    virtual void * get(char* e, int index);
private:
    using Base::get;
};

Это запрещает пользователю Derived вызывать Derived::get(char* e) при отключении предупреждения:

Derived der;
der.get("", 0); //Allowed
der.get("");    //Compilation error