Возможный дубликат:
Как удалить дублирование кода между похожими константными и неконстантными функциями-членами?
у меня два члена
A &B::GetA (int i)
{
return *(m_C[m_AtoC[i]]);
}
const A &B::GetA (int i) const
{
return *(m_C[m_AtoC[i]]);
}
сейчас я просто дублирую код, но, может быть, есть хороший способ сделать это. Я определенно не хочу иметь дело с приведением типа от константного к неконстантному.
РЕДАКТИРОВАТЬ: Итак, я хочу позвонить один член от другого, чтобы избежать дублирования кода.
[Обратите внимание на исправление; извините за неправильное понимание изначально.]
Это подходящая ситуация для использования const_cast
и это позволяет вам дедуплицировать код, перенаправляя вызов из неконстантной функции в соответствующую константную функцию:
A & B::GetA(int index)
{
return const_cast<A &>(static_cast<B const *>(this)->GetA(index));
}
Важно отметить, что это должно быть сделано только в одном направлении: вы можете реализовать non-const
метод с точки зрения константы, но не наоборот: постоянный вызов GetA()
получает постоянную ссылку на рассматриваемый объект, но так как у нас есть дополнительная информация, что это на самом деле ОК, чтобы изменить объект, мы можем безопасно отбросить константу из результата.
В Скотте Мейере есть даже глава, посвященная именно этой технике. Эффективный C ++.
Вы могли бы сделать что-то вроде:
class B {
public:
A& GetA (int index) { return GetA_impl(index); }
const A& GetA (int index) const { return GetA_impl(index); }
private:
A& GetA_impl (int index) const { return *(m_C[m_AtoC[i]]); }
};
Я не уверен, что это действительно стоит усилий в этом случае, но это может быть полезно, если потенциально дублированный код становится более сложным.
Вы можете избежать const_cast с небольшим шаблоном метапрограммирования.
// This meta function returns a const U if T is const, otherwise returns just U.
template <typename T, typename U>
make_same_const<T, U>
{
typedef typename std::conditional<
std::is_const<T>::value,
typename std::add_const<U>::type,
U
>::type type;
};// Generic version of a function. Constness of return type depends on
// constness of T.
// This is a static member template of B.
template <typename T>
make_same_const<T, A>::type& B::GetA(T& obj, int i)
{
return *(obj.m_C[obj.m_AtoC[i]]);
}
A& B::GetA(int i) { return B::GetA(*this, i); }
A const& B::GetA(int i) const { return B::GetA(*this, i); }
IMO, этого недостаточно кода (или сложности), чтобы стоить дедупликации.
Как вы можете видеть в обоих const_cast
основанные на решениях дольше чем оригинальный код.
Если у вас длинное или более сложное выражение, о котором вы действительно беспокоитесь, покажите его.
Принимая тела GetA()
а также GetA() const
идентичны (что означает GetA()
не модифицирует *this
), вы можете безопасно использовать один const_cast
Чтобы реализовать версию const, используя неконстантную версию:
const A& B::GetA() const {
return const_cast<B*>(this)->GetA();
}
Неконстантный GetA()
не изменяет объект, поэтому вызывает его на const B
объект не является неопределенным Неконстантная ссылка, возвращаемая неконстантной GetA()
превращается в const&
перед возвращением из GetA() const
так что там нет опасности неопределенного поведения.
Как насчет
const A &B::GetA (int index) const
{
return *(const_cast<B*>(this)->GetA(index));
}