Переопределить количество параметров чисто виртуальных функций - PullRequest
16 голосов
/ 27 мая 2010

Я реализовал следующий интерфейс:

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)). Есть ли способ сделать это?

Ответы [ 5 ]

16 голосов
/ 27 мая 2010

Это проблема, которую я запускал несколько раз.

Это невозможно, и по веским причинам, но есть способы достичь по существу того же самого. Лично я сейчас использую:

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
8 голосов
/ 27 мая 2010

Даже если бы такая вещь была возможна, больше не имеет смысла иметь ее как виртуальную функцию, поскольку производные экземпляры нельзя вызывать полиморфно через указатель на базовый класс.

4 голосов
/ 27 мая 2010

не думаю, что это будет возможно, потому что вы никогда не сможете связать его обратно с переменной. Это то, что я имею в виду

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.
2 голосов
/ 27 мая 2010

Я знаю, что есть принятый ответ, но есть один (безобразный) способ добиться того, чего вы хотите, хотя я бы не рекомендовал это:

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.

Этот метод подвержен ошибкам, поскольку вы должны сопоставлять типы аргументов значения с реальными типами аргументов.

1 голос
/ 27 мая 2010

Вам нужно будет добавить перегрузку Callback в базовый класс, который принимает эти параметры.Также было бы возможно делать плохие вещи, например, принимать void * или передавать необработанный указатель на байты.Единственный сценарий, в котором допустимо изменять сигнатуру виртуальной функции, - это когда вы переопределяете возвращаемое значение на нечто полиморфное к исходному возвращаемому значению, например * this.

...