Вызов версии неконстантного члена от const

Возможный дубликат:
Как удалить дублирование кода между похожими константными и неконстантными функциями-членами?

у меня два члена

A &B::GetA (int i)
{
return *(m_C[m_AtoC[i]]);
}

const A &B::GetA (int i) const
{
return *(m_C[m_AtoC[i]]);
}

сейчас я просто дублирую код, но, может быть, есть хороший способ сделать это. Я определенно не хочу иметь дело с приведением типа от константного к неконстантному.

РЕДАКТИРОВАТЬ: Итак, я хочу позвонить один член от другого, чтобы избежать дублирования кода.

5

Решение

[Обратите внимание на исправление; извините за неправильное понимание изначально.]

Это подходящая ситуация для использования const_castи это позволяет вам дедуплицировать код, перенаправляя вызов из неконстантной функции в соответствующую константную функцию:

A & B::GetA(int index)
{
return const_cast<A &>(static_cast<B const *>(this)->GetA(index));
}

Важно отметить, что это должно быть сделано только в одном направлении: вы можете реализовать non-const метод с точки зрения константы, но не наоборот: постоянный вызов GetA() получает постоянную ссылку на рассматриваемый объект, но так как у нас есть дополнительная информация, что это на самом деле ОК, чтобы изменить объект, мы можем безопасно отбросить константу из результата.

В Скотте Мейере есть даже глава, посвященная именно этой технике. Эффективный C ++.

2

Другие решения

Вы могли бы сделать что-то вроде:

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]]); }
};

Я не уверен, что это действительно стоит усилий в этом случае, но это может быть полезно, если потенциально дублированный код становится более сложным.

1

Вы можете избежать 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); }
1

IMO, этого недостаточно кода (или сложности), чтобы стоить дедупликации.

Как вы можете видеть в обоих const_castоснованные на решениях дольше чем оригинальный код.

Если у вас длинное или более сложное выражение, о котором вы действительно беспокоитесь, покажите его.

0

Принимая тела 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так что там нет опасности неопределенного поведения.

0

Как насчет

const A &B::GetA (int index) const
{
return *(const_cast<B*>(this)->GetA(index));
}
0
По вопросам рекламы [email protected]