使用常量和非常量函数 - C ++

时间:2010-02-14 06:48:36

标签: c++ const

我有3节课。在它最简单的形式,它看起来像,

class tree
{
public:
    tree_node* find_node(const std::string& text) {
       return factory.find(text);
    }
private:
    tree_node_factory factory;
}

class tree_node
{
public:
    tree_node(const std::string& text) : text_(text) {}

    const std::string& text() const {
       return text_;
    }

    void set_parent(const tree_node* new_parent);

private:
    std::string text_;
}

class tree_node_factory
{
public:
    tree_node* find(const std::string& text);
private:
    std::vector<tree_node*> allocated_nodes;
}

我不想允许tree的用户修改tree_node等方法返回的find_node。所以我更改了find_nodetree_node_factory::find

const tree_node* find_node(const std::string& text) const {
    return factory.find(text);
}

const tree_node* find(const std::string& text) const;

问题是tree内部应该能够修改节点并处理像set_parent这样的方法。但由于工厂只返回const个节点,我最终将find的另一个重载(非常量版本)添加到工厂中。

tree_node* find(const std::string& text);

我想知道这是处理这类问题的正确方法吗?我看到代码在const和非const版本中都是重复的。

有什么想法..?

2 个答案:

答案 0 :(得分:7)

Scott Meyers的书 Effective C ++ 中的第3项演示了一种删除此代码重复的方法。基本上,在你的非const函数中,你将const添加到this,调用const版本,然后将const转换掉。这很安全;虽然写一个const变量会导致未定义的行为,因为this最初是非const的,所以没关系。

示例:

const std::string& operator[](size_t index) const
{
    // some other code

    // since `this` isn't really const, this is modifiable 
    return mData[index]; 
}

std::string& operator[](size_t index)
{
    return const_cast<std::string&> // (3) take const off result
            (static_cast<const my_type&> // (1) add const
            (*this)[index]); // (2) use const version

}

通常它都会在一条线上。你也可以为它做一个实用工具。

请注意:如果const版本返回“真正的”const对象,则此方法显然会导致未定义的行为。返回值的常量必须由this引用的对象的常量反映。这是破碎的代码:

const std::string& operator[](size_t index) const
{
    static const std::string constString = "Don't modify me.";

    if (index == 0)
    {
        // even though `this` isn't really const, this is NOT modifiable
        return constString; 
    }

    return mData[index - 1];
}

std::string& operator[](size_t index)
{
    return const_cast<std::string&> // (3) !!! take const off result !!!
            (static_cast<const my_type&> // (1)
            (*this)[index]); // (2)

}

在实践中,我们避免全球状态,所以这很少是一个问题。无论如何,检查是微不足道的。

答案 1 :(得分:3)

不幸的是,C ++没有工具(除了宏)来消除函数重载中的源代码重复,这些重载看起来大致相同但是const的不同。但是,您可以使用另一个函数const_cast实现其中一个函数。