Я уже много лет преподаю класс программирования C ++, и одна из самых сложных вещей, которые нужно объяснить студентам, - это перегрузка констант. Я обычно использую пример векторного класса и его функцию operator []
:
template <typename T> class Vector {
public:
T& operator[] (size_t index);
const T& operator[] (size_t index) const;
};
У меня практически нет проблем с объяснением, почему это две версии оператора []
необходимы, но, пытаясь объяснить, как объединить две реализации вместе, я часто трачу много времени на языковые арканы. Проблема в том, что единственное хорошее, Надежный способ, которым я знаю, как реализовать одну из этих функций с точки зрения другой, - это трюк 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_cast
, почему он уместен здесь и почему он почти повсеместно неуместен в других местах, обычно занимает у меня от пяти до десяти минут лекции, а понимание всего этого выражения часто требует больше усилий, чем разница между const T *
и T * const
. Я считаю, что студенты должны знать о перегрузке констант и о том, как это сделать без ненужного дублирования кода в двух функциях, но этот трюк кажется немного излишним для вводного курса программирования на C ++.
Мой вопрос - есть ли более простой способ реализовать const
-перегруженные функции в терминах друг друга? Или есть более простой способ объяснить учащимся этот существующий трюк?