Я реализовал следующий интерфейс:
template <typename T>
class Variable
{
public:
Variable (T v) : m_value (v) {}
virtual void Callback () = 0;
private:
T m_value;
};
Надлежащий производный класс был бы определен как это:
class Derived : public Variable<int>
{
public:
Derived (int v) : Variable<int> (v) {}
void Callback () {}
};
Однако я хотел бы получить классы где Callback
принимает различные параметры (например: void Callback (int a, int b))
. Существует ли способ сделать это?
С этой проблемой я сталкивался несколько раз.
Это невозможно, и на то есть веские причины, но есть способы добиться по сути того же самого. Лично я сейчас использую:
struct Base
{
virtual void execute() = 0;
virtual ~Base {}
};
class Derived: public Base
{
public:
Derived(int a, int b): mA(a), mB(b), mR(0) {}
int getResult() const { return mR; }
virtual void execute() { mR = mA + mB; }
private:
int mA, mB, mR;
};
В действии:
int main(int argc, char* argv[])
{
std::unique_ptr<Base> derived(new Derived(1,2));
derived->execute();
return 0;
} // main
Даже если бы такая вещь была возможна, больше не имеет смысла иметь ее как виртуальную функцию, поскольку производные экземпляры не могут быть вызваны полиморфно через указатель на базовый класс.
Вам нужно будет добавить перегрузку Callback в базовый класс, который принимает эти параметры. Также можно было бы делать плохие вещи, например принимать void * или передавать необработанный указатель на байты. Единственный сценарий, в котором допустимо изменение сигнатуры виртуальной функции, - это когда вы переопределяете возвращаемое значение на что-то, полиморфное исходному возвращаемому значению, например. *это.
не думаю, что это будет возможно, потому что вы никогда не сможете связать это обратно с переменной. Это то, что я имею в виду
int a=0; int b = 0;
Variable<int>* derived = new Derived();
derived->Callback(a, b); //this won't compile because Variable<int> does not have Callback with 2 vars.
Я знаю, что это общепринятый ответ, но есть один (уродливый) способ достичь того, что вы хотите, хотя я бы не рекомендовал его:
template <typename T>
class Variable
{
public:
Variable (T v) : m_value (v) {}
virtual void Callback (const char *values, ...) = 0;
private:
T m_value;
};
class Derived : public Variable<int>
{
public:
Derived (int v) : Variable<int> (v) {}
virtual void Callback (const char *values, ...) {
}
};
Теперь вы можете использовать:
int a=0;
double b = 0;
Variable<int>* derived = new Derived(3);
derived->Callback("");
derived->Callback("df", a, b);
Вам нужен аргумент values, чтобы получить остальные аргументы внутри метода. Также необходимо знать типы аргументов и передавать их, как это делает printf.
Этот метод склонен к ошибкам, поскольку необходимо сопоставить типы аргументов в values с реальными типами аргументов.