Я хотел бы включить предупреждение C4263 (Visual C ++) в нашей кодовой базе, однако предупреждение выдает некоторые ложные срабатывания. Мы хотели бы отключить предупреждение, чтобы исчезли только ложные срабатывания. Я попытался упростить проблему с помощью некоторого общего кода:
class B {
public:
virtual void funcA();
virtual void funcB();
};class D : public B
{
virtual void funcA(int);
virtual void funcB(int);
};
С этим кодом мы получаем следующие предупреждения:
void D :: funcA (int) ‘: функция-член не переопределяет виртуальную функцию-член базового класса
void D :: funcB (int) ‘: функция-член не переопределяет виртуальную функцию-член базового класса
Я пытаюсь добиться того, чтобы отключить предупреждение для funcA (или funcB) и позволить этому классу повлиять на него.
Я пытался положить
#pragma warning(push)
#pragma warning(disable:4263)
.
.
.
#pragma warning(pop)
вокруг funcA, но это не решает проблему. Если прагмы охватывают весь класс, то оба предупреждения исчезают.
Есть идеи?
Это странная ошибка, учитывая документацию к ней:
https://msdn.microsoft.com/en-us/library/ay4h0tc9.aspx?f=255&MSPPError = -2147217396
‘функция’: функция-член не переопределяет виртуальный базовый класс
функция-членОпределение функции класса имеет то же имя, что и виртуальная функция в
базовый класс, но не тот же номер или тип аргументов. это
эффективно скрывает виртуальную функцию в базовом классе.
Последнее предложение является интересным, и оно подсказало мне, что если вы раскроете функции базового класса, предупреждение больше не появится.
И это действительно так. Следующий код не выводит C4263:
class B {
public:
virtual void funcA();
virtual void funcB();
};
class D : public B
{
using B::funcA;
using B::funcB;
virtual void funcA(int);
virtual void funcB(int);
};
Предупреждение кажется немного странным. Если вы отправляете из указателя базового класса, не имеет значения, какие функции скрывает производный класс, поскольку они не будут скрыты при использовании указателя базового класса. Но в этом и заключается ответ!
То, что на самом деле происходит здесь, это то, что компилятор угадывает ваши намерения. Поскольку вы вводите новую подпись, это означает, что вы будете использовать либо полиморфную, либо неполиморфную диспетчеризацию, используя производный указатель (а не базовый указатель). Если бы вы этого не делали, было бы невозможно вызвать вашу перегрузку. Компилятор считает, что если вы делаете это, вы будете скрывать не переопределенные функции. И это то, о чем идет речь.
В примере:
struct Base
{
virtual void DoThing(int)
{
std::cout << "INT " << std::endl;
}
};
struct Derived: public Base
{
virtual void DoThing(char) // Add a function to handle chars
{
std::cout << "CHAR " << std::endl;
}
};
int main()
{
Derived *derived = new Derived;
Base *base = derived;
base->DoThing(1);
derived->DoThing(1);
derived->DoThing('a');
}
Это выводит:
INT CHAR CHAR
Возможно, мы хотели добавить перегрузку для обработки другого случая, но вместо этого скрывали все существующие перегрузки. Предупреждение является правильным, учитывая правила языка. Предупреждение не точное, тривиально определить случаи, когда оно не вызывается, но должно. Это фактически делает противоположность ложным предупреждениям 🙂
Чтобы опровергнуть это предупреждение, следует использовать объявление using.