У меня есть производный класс, где я хочу, чтобы одна из функций переопределяла свою версию в базовом классе, но имела другую подпись.
Простой пример:
#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), и эта функция критична к производительности. Есть ли способ лучше?
Эти сигнатуры функций не идентичны:
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);
// ...
}
Какой в этом смысл? Причина, по которой вы используете виртуальную функцию, заключается в том, что от вызывающей стороны требуется только знать базовый класс и, следовательно, только сигнатуру базового класса.
Другими словами, код, который имеет, скажем, 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
отмечать основные функции.
и эта функция критична к производительности.