Я преподаю класс программирования C ++ уже много лет, и одна из самых хитрых вещей, которые нужно объяснить студентам, - это перегружать их.Я обычно использую пример вектороподобного класса и его функции operator[]
:
template <typename T> class Vector {
public:
T& operator[] (size_t index);
const T& operator[] (size_t index) const;
};
У меня практически нет проблем с объяснением, почему необходимы две версии функции operator[]
, нопытаясь объяснить, как объединить две реализации вместе, я часто трачу много времени на изучение языка.Проблема в том, что единственный хороший и надежный способ, которым я знаю, как реализовать одну из этих функций в терминах другой, - это трюк const_cast
/ static_cast
:
template <typename T> const T& Vector<T>::operator[] (size_t index) const {
/* ... your implementation here ... */
}
template <typename T> T& Vector<T>::operator[] (size_t index) {
return const_cast<T&>(static_cast<const Vector&>(*this)[index]);
}
Проблема с этимустановка состоит в том, что это чрезвычайно сложно объяснить и совсем не интуитивно очевидно.Когда вы объясняете это как «приведение к const, затем вызываете версию const, а затем отбрасываете constness», это немного легче понять, но фактический синтаксис пугающий.Объяснение, что такое const_cast
, почему это уместно здесь, и почему это почти повсеместно неуместно в других местах, обычно занимает от пяти до десяти минут лекционного времени, и для понимания всего этого выражения часто требуется больше усилий, чем от разницы между const T*
и T* const
.Я чувствую, что студентам нужно знать о константной перегрузке и о том, как это сделать, не дублируя код в двух функциях без необходимости, но этот трюк кажется немного чрезмерным во вводном курсе по программированию на C ++.
У меня такой вопрос- есть ли более простой способ реализации перегруженных const
функций в терминах друг друга?Или есть более простой способ объяснить этот существующий трюк студентам?