Возможный дубликат:
Как удалить дублирование кода между похожими константными и неконстантными функциями-членами?
В следующем примере:
template<typename Type, unsigned int Size>
class MyClass
{
public: inline Type& operator[](const unsigned int i)
{return _data[i];}
public: inline const Type& operator[](const unsigned int i) const
{return _data[i];}
protected: Type _data[Size];
};
постоянный и неконстантный operator[]
реализуются независимо.
С точки зрения дизайна лучше иметь:
Если решение 2) лучше, каким был бы код данного примера?
Вы не можете иметь ни одну реализацию, вызывающую другую, не отбрасывая константу, что является плохой идеей.
const
метод не может вызвать не-const
один.
Затем на-const
метод не может вызвать const
один, потому что нужно будет привести тип возвращаемого значения.
Это хорошо известный и широко принятый шаблон реализации, когда неконстантный метод реализуется через его константный аналог, как в
class some_class {
const some_type& some_method(arg) const
{
...;
return something;
}
some_type& some_method(arg)
{
return const_cast<some_type&>(
const_cast<const some_class *>(this)->some_method(arg));
}
};
Это совершенно приемлемый метод, который по существу не имеет сопоставимых (в удобстве) альтернатив в ситуациях, когда тело метода является относительно тяжелым. Зло const_cast
значительно меньше, чем зло дублированного кода.
Однако, когда тело метода по существу является однострочным, может быть лучше придерживаться явно идентичной реализации, просто чтобы избежать этого едва читаемого набора const_cast
s.
Вероятно, можно придумать формально лучше разработанное решение без кастинга, реализованное по принципу
class some_class {
template <typename R, typename C>
static R& some_method(C *self, arg)
{
// Implement it here in terms of `self->...` and `R` result type
}
const some_type& some_method(arg) const
{
return some_method<const some_type>(this, arg);
}
some_type& some_method(arg)
{
return some_method<some_type>(this, arg);
}
};
но для меня это выглядит даже менее элегантно, чем подход с const_cast
,
К сожалению, шаблоны «constness» не работают, но я все же думаю, что стоит рассмотреть общую идею:
// NOTE: this DOES NOT (yet?) work!
template <const CV>
Type CV& operator[](unsigned int index) CV {
...
}
На данный момент я бы реализовал тривиальные функции только дважды. Если код станет более сложным, чем строка или две, я добавлю детали в шаблон функции и делегирую реализацию.