У меня есть следующий простой класс
class base
{
public:
int x;
base &set(int y)
{
x = y;
return *this;
}
};
и хотите создать новый с дополнительной функциональностью, скажем, для печати значения х. Итак, я делаю:
class derived : public base
{
public:
void print()
{
cout << x << endl;
}
};
Теперь в основной программе я хочу сделать что-то вроде
D.set(2).print();
однако компилятор жалуется, что в базе классов нет члена с именем print.
Если я попытаюсь использовать ковариантные возвращаемые типы и напишу два класса как
class base
{
public:
int x;
virtual base &set(int y)
{
x = y;
return *this;
}
};
class derived : public base
{
public:
derived &set(int y)
{
x = y;
return *this;
}
void print()
{
cout << x << endl;
}
};
тогда оператор работает просто отлично, но я был вынужден переписать одно и то же тело функции для ‘set’ в обоих классах, хотя единственное, что меняется, — это тип возвращаемого значения.
Если позже мне потребуется изменить функциональность base :: set, то мне придется пройти через все производные классы, чтобы изменить функцию ‘set’ … Есть ли способы избежать этого? Заранее спасибо!
C ++ работает, как вы говорите, и вы говорите в своем базовом классе set
вернуть base&
Так вот что делает C ++. Но чтобы решить это, у вас есть много способов.
Во-первых, вы не обязаны выполнять функцию virtual
переопределить его в производном классе (обратите внимание, что виртуальный вызов немного медленнее, чем обычные вызовы).
Во-вторых, вы можете обратиться к реализации базового класса как base::set
поэтому код будет следующим:
class base {
...
base& set( int x ) {...}
};
class derived : public base {
derived& set( int x ) {
return static_cast<derived&>( base::set(x) );
}
};
В зависимости от ваших обстоятельств вы можете использовать CRTP:
template <class D>
class base {
D& set(int x) {
…;
return *static_cast<D*>(this);
}
};
class derived : base<derived> { … };