Заменить число параметров чистых виртуальных функций

158
9

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


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

спросил(а) 2021-01-25T19:18:25+03:00 4 месяца, 4 недели назад
1
Решение
159

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


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


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

ответил(а) 2021-01-25T19:18:25+03:00 4 месяца, 4 недели назад
124

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

ответил(а) 2021-01-25T19:18:25+03:00 4 месяца, 4 недели назад
99

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


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.

ответил(а) 2021-01-25T19:18:25+03:00 4 месяца, 4 недели назад
77

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


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);

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


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

ответил(а) 2021-01-25T19:18:25+03:00 4 месяца, 4 недели назад
63

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

ответил(а) 2021-01-25T19:18:25+03:00 4 месяца, 4 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема