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