Переопределить чистую виртуальную функцию с другим параметром производного типа - PullRequest
1 голос
/ 07 мая 2020

Есть много вопросов по этому топи c, но я не нашел решения для своего следующего вопроса:

У меня есть следующие классы:

1 ) Чистый виртуальный класс

class Employee {
private:
    vector<Employee> vec_employee;

public:
    Employee() {};
    virtual ~Employee() {};
    virtual void set_vec_subordinate(vector<Employee> vec_employee) = 0;
};

2) Производный класс

class Worker : Employee{ private: public: };

3) Другой производный класс, который должен переопределить чистый виртуальный метод из Employee

class Manager : Employee {
private:
public:
    inline void set_vec_subordinate(vector<Worker> vec_employee) override { this->set_vec_subordinate(vec_employee); };
};

Я пытаюсь переопределить чисто виртуальный метод, но использовать «другой» параметр. Так что все еще новичок в C ++, но я думаю, что должен быть способ сделать это, особенно потому, что другой параметр относится к типу Worker, который является производным классом от Employee .

1 Ответ

1 голос
/ 07 мая 2020

Невозможно сделать в точности то, что вы планируете делать (и для этого есть веская причина).

Ваш код также по своей сути нарушен, поскольку вы используете тип vector<Employee>, для которого требуются объекты типа Employee, которые не могут существовать, поскольку Employee является абстрактным классом. Вы можете wi sh использовать vector ссылочного типа, например, vector<shared_ptr<Employee>>. (Остальная часть этого ответа замалчивает этот факт, чтобы сделать его более читабельным.)

Обратите внимание, что void Manager::set_vec_subordinate(vector<Worker> vec_employee) override { this->set_vec_subordinate(vec_employee); }; вызовет бесконечное l oop (вероятно, приведет к переполнению стека) при вызове, поскольку он будет просто продолжать называть себя.

Класс Employee имеет договор со своими пользователями, в котором говорится, что следующий код должен быть действительным (при условии, что заданы функции get_boss и get_workers):

Employee& boss = get_boss();
vector<Employee> subordinate_vec = get_workers();
boss.set_vec_subordinate(subordinate_vec);

Теперь это может не иметь никакого смысла c semanti для вашего приложения, но синтаксис языка программирования означает, что это должно быть возможно . Некоторые языки программирования ( не C ++! ) допускают ковариантные вызовы, подобные этому:

Employee& boss = get_boss();
vector<Worker> subordinate_vec = get_workers();
boss.set_vec_subordinate(subordinate_vec);  // Invalid C++: `vector<Worker` cannot be converted to `vector<Employee>` implicitly

Хотя действительно возможно создать контейнер на C ++, который ведет себя таким образом, чтобы он использовал возможно, с этим легче справиться, сделав функцию set_vec_subordinate шаблоном, который требует произвольного контейнера объектов, которые неявно конвертируются или являются производными от Employee, а затем просто преобразовать объекты во время операции копирования (поскольку в любом случае вектор не может перемещаться).

Вторая идея состоит в том, что должна быть возможность изменить сигнатуру функции при ее замещении. Это возможно в C ++ путем реализации базового случая (который должен быть двоично совместим с - или равным - сигнатуры версии Employee, так как она будет вызываться и для этого случая), а затем добавлением дополнительных перегрузок. . Например, вы можете сделать что-то вроде:

class Manager : Employee {
private:
public:
    inline void set_vec_subordinate(vector<Employee> vec_employee) override { this->vec_employee = std::move(vec_employee); };
    inline void set_vec_subordinate(vector<Worker> const& vec_worker) {
        vec_employee = std::vector<Employee>(vec_worker.begin(), vec_worker.end());  // copy convert all elements
    };
};
...