Производный класс не переопределяет виртуальную функцию с другой подписью

У меня есть производный класс, где я хочу, чтобы одна из функций переопределяла свою версию в базовом классе, но имела другую подпись.
Простой пример:

#include "stdio.h"
bool use_foo = false;

class Foo {
public:
virtual int func(double x) { printf ("%f in Foo!\n", x); }
};

class Bar : public Foo {
public:
int func(short x) { printf ("%d in Bar!\n", x); }
};

int main () {
Foo* A;
if (use_foo)
A = new Foo;
else
A = new Bar;

A->func(2);
return 0;
}

Приведенный выше код вызовет копию базового класса, даже если A был выделен как производный класс:

> g++ test.cpp -o test -O3 && ./test
2.000000 in Foo!

Потому что (насколько я понимаю) аргумент может быть преобразован так, чтобы соответствовать сигнатуре базового класса, и производный класс не переопределит его из-за этой разницы (но не так ли скрывать это в таком случае?). Если я изменю функцию базового класса, чтобы иметь short как аргумент, производный класс действительно может переопределить его.

Есть ли простой способ убедить вызов использовать правильную функцию, основанную на указателе? Я мог бы добавить еще одну функцию, как это:

class Bar : public Foo {
public:
int func2(short x) { printf ("%d in Bar!\n", x); }
int func(double x) { func2(x); }
};

Но тогда я бы все время конвертировал аргументы (short-> double-> short), и эта функция критична к производительности. Есть ли способ лучше?

2

Решение

Эти сигнатуры функций не идентичны:

virtual int func(double x) {...} // base class
int func(short x) {...} // derived class

Один использует double параметр, другой использует short, За переопределение Чтобы произошло несколько условий должны быть выполнены. идентичный типы параметров базовой и производных функций, являющихся одним из них. Ниже приводится выдержка из книги Скотта Мейерса «Modern Effective C ++» о всех требованиях:

• Функция базового класса должна быть виртуальной.

• База и производные
имена функций должны быть идентичны (кроме случая деструкторов).

• Типы параметров базовой и производных функций должны быть
идентичны.

• Константность базовых и производных функций должна быть
идентичны.

• Типы возврата и спецификации исключений базы
и производные функции должны быть совместимы.

Или же, сделайте сигнатуры одинаковыми и выполните приведение внутри тела производной функции:

int func(double x) override {
short temp = static_cast<short>(x);
// ...
}
3

Другие решения

Какой в ​​этом смысл? Причина, по которой вы используете виртуальную функцию, заключается в том, что от вызывающей стороны требуется только знать базовый класс и, следовательно, только сигнатуру базового класса.

Другими словами, код, который имеет, скажем, Foo& или Foo* или std::unique_ptr<Foo>Только знает о double версия вашей функции в любом случае. Это пройдет double когда он звонит funcпотому что что еще он должен делать?

Возможно что ты действительно хочу сделать, это реализация подкласса функции для преобразования double к short, Вот пример для этого, который также избавляется от printf в пользу безопасного типа потока C ++:

class Bar : public Foo {
public:
int func(double x) { std::cout << static_cast<short>(x) << " in Bar!\n"; }
};

Обратите внимание, что начиная с C ++ 11, вам рекомендуется использовать override отмечать основные функции.

и эта функция критична к производительности.

  1. Должна ли вообще критичная к производительности функция быть виртуальной?
  2. Вы на самом деле измеренный скорость? Есть ли заметная задержка? Или компьютеры все равно слишком быстрые?
1

По вопросам рекламы [email protected]