从const调用nonconst成员版本

时间:2013-01-18 14:28:28

标签: c++ const overloading

  

可能重复:
  How do I remove code duplication between similar const and non-const member functions?

我有两个成员

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到非const的类型转换。

编辑:所以我想调用另一个成员来避免代码重复。

6 个答案:

答案 0 :(得分:2)

[注意更正;对不起,最初得错了。]

这是使用const_cast的合适情况,它允许您通过将调用从非const函数转发到相应的const函数来对代码进行重复数据删除:

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

重要的是要注意,这应该只在一个方向上完成:你可以用常量方法实现non-const方法,但不能反过来实现:GetA()的常量调用获得对相关对象的持续引用,但由于我们有其他信息,它实际确定可以改变对象,我们可以安全地从结果中抛弃const。

在Scott Meyer的 Effective C ++ 中,甚至还有一章正是关于这种技术。

答案 1 :(得分:1)

您可以执行以下操作:

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

我不确定在这种情况下确实值得付出努力,但如果可能重复的代码变得更复杂,这可能很有用。

答案 2 :(得分: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); }

答案 3 :(得分:0)

怎么样

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

答案 4 :(得分:0)

IMO这个代码(或复杂性)不足以进行重复数据删除。

正如您在基于const_cast的解决方案中所看到的,转换表达式实际上更长而不是原始代码。

如果你有一个更长或更复杂的表达,你真的很担心,但请展示它。

答案 5 :(得分:0)

假设GetA()GetA() const的正文相同(这意味着GetA()不会修改*this),您可以安全地使用一个const_castconst A& B::GetA() const { return const_cast<B*>(this)->GetA(); } 使用非const的实现const版本:

GetA()

非const const B不会修改对象,因此在GetA()对象上调用它不是未定义的。非const const&返回的非const引用在返回GetA() const之前转换为{{1}},因此也没有未定义行为的危险。