Наследование чисто виртуальных методов с разными аргументами в разных производных классах - PullRequest
0 голосов
/ 13 декабря 2018

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

Мой текущий код перегружает функции в базовом классе, что происходиткак:

class Base {
protected:
    virtual void function(arg_set_first) = 0;
    virtual void function(arg_set_second) = 0;
}

class Derived_First: public Base {
private:
    void function(arg_set_first);
    void function(arg_set_second) { } // do nothing
}

class Derived_Second: public Base {
private:
    void function(arg_set_first) { } // do nothing
    void function(arg_set_second);
}

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

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

1 Ответ

0 голосов
/ 13 декабря 2018

Строго говоря, вы не можете сделать это в C ++ - список параметров метода (и типы этих параметров) считаются частью сигнатуры метода , и поэтомуВиртуальный метод дочернего класса может переопределить / реализовать виртуальный метод родительского класса, только если они оба имеют одинаковое имя и одинаковые точные параметры.

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

class Base {
protected:
    virtual void function(const std::map<std::string, std::variant> & args) = 0;
}

С учетом вышесказанного у вас есть метод, который может принимать любой набор именованных аргументов в форме набора пар ключ-значение.Затем дочерние классы (и их вызывающие) должны были согласовать, какие имена аргументов и значения аргументов использовать.Недостатком этого подхода является то, что он менее эффективен и сложнее в использовании (вызывающий должен создавать и заполнять std::map каждый раз, когда он хочет вызвать метод, а метод должен проверять содержимое std:map и рисунокчто с ними делать);однако если гибкость является вашей главной задачей, а производительность - нет (например, потому что метод не будет вызываться очень часто), этот подход может работать хорошо.

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

class BaseFirst {
protected:
    virtual void function(arg_set_first) = 0;
}

class BaseSecond {
protected:
    virtual void function(arg_set_second) = 0;
}

class BaseBoth : public BaseFirst, public BaseSecond {
};

class Derived_First: public BaseFirst {
private:
    virtual void function(arg_set_first) {...}
};

class Derived_Second: public BaseSecond {
private:
    virtual void function(arg_set_second) {...}
};

class Derived_Both: public BaseBoth {
private:
    virtual void function(arg_set_first) {...}
    virtual void function(arg_set_second) {...}
};

Поскольку любой конкретный фрагмент вызывающего кода знает, какой из functionметоды, которые он захочет вызвать (и которые он не будет), он может просто указать соответствующие типы указателей / ссылок в своем API (например, BaseFirst *, BaseSecond * или BaseBoth *), чтобы отразить его требования, иКомпилятор гарантирует вам, что только объекты, которые действительно соответствуют этим требованиям, могут быть переданы ему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...