Когда мой базовый класс и производные имеют одну и ту же функцию, ДОЛЖЕН ли он быть виртуальным?

Так что у меня есть проект, над которым я работаю с довольно иерархической структурой. В базовом классе этого есть функция reset (), которая вызывается во всех производных классах. Все, что меня смущает, так это то, что, поскольку этот сброс в производном классе в основном просто сбрасывает его закрытые переменные, а затем вызывает функцию reset () предыдущего (более высокого) класса, должна ли функция сброса быть виртуальной?

Например.

class Base
{
private:
int some;
public:
void reset();
};

class Derive : public Base
{
private:
int some1;
public:
void reset();
};

class Derive_two : public Derive
{
private:
int some2;
public:
void reset();
};

Таким образом, функция сброса класса Derive_two будет выглядеть следующим образом.

void Derive_two::reset()
{
some2 = 10;
Derive::reset();
}

Правильно ли этот код? Или функция reset () должна быть виртуальной?

Любая и помощь приветствуется, спасибо.

1

Решение

Правильно ли этот код?

Возможно нет. Это не полиморфный; Это означает, что вызов функции через указатель или ссылку на Base будет вызывать только версию, объявленную в Base, Итак, следующее:

void DoStuffAndReset(Base & b) {
DoStuff(b);
b.reset();
}

Derive d;
DoStuffAndReset(d);

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

Или функция reset () должна быть виртуальной?

Это должно быть, если вы хотите переопределить его, и чтобы переопределенная версия вызывалась через указатель или ссылку на базовый класс; что, вероятно, поведение, которое вы хотите. Делая reset Виртуальный, мой пример полностью сбросил бы объект, каким бы он ни был.

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

Base * b = new Derive;
delete b;

который можно исправить, добавив деструктор к public часть Base:

virtual ~Base() {}  // assuming it doesn't need to do anything
2

Другие решения

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

void f( Base &b )
{
b.reset();
}

int main()
{
Derive d1;
f( d1 );
Derive_two d2;
f( d2 );
}

Таким образом, вопрос заключается в том, хотите ли вы, чтобы функция f сбрасывала только элементы данных базового подобъекта, или она должна сбрасывать элементы данных объекта, переданного ей по ссылке.

1

Этот похожий вопрос StackOverload объясняет виртуальные методы и дает отличный пример:

Зачем нам нужны виртуальные функции в C ++?

Дайте мне знать, если это не ответит на ваш вопрос.

0