c++ перегруженная виртуальная функция предупреждение по 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]

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

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

- Это лязг верно? Зачем?

Примечание это на MacOS X, работает последняя версия Xcode.

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

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

4   52   2013-08-29 19:32:57

4 ответа:

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

struct chart; // let's 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);
};

Р. Мартиньо Фернандес решение совершенно справедливо, если вы действительно хотите принести 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

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

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

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

этот пример кода не компилируется:

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

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


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