С++ перегружено предупреждение виртуальной функции 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.
Ответы
Ответ 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