tags:

views:

144

answers:

2

I have 3 classes. In it's simplest form, it looks like,

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

I don't want to allow users of tree to modify the tree_node returned by methods like find_node. So I changed, find_node and tree_node_factory::find to,

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

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

Problem is tree internally should be able to modify the nodes and work on methods like set_parent. But since factory returns only const nodes, I ended up with adding another overload (non const version) of find into the factory.

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

I am wondering is this the correct way to handle these kind of problems? I see the code is getting duplicated in the const and non-const versions.

Any thoughts..?

+3  A: 

Unfortunately C++ has no tools (besides macros) for eliminating source code duplication in function overloads that look largely identical but differ in constness. You can, however, implement one of the functions using the other and const_cast.

Tronic
+5  A: 

Item 3 in Scott Meyers Effective C++ talks about a way to remove this code duplication. Basically, in your non-const function you will add const, call the const version, then cast the const away. This is safe; writing to a const-variable leads to undefined behavior, but because we were originally non-const, we're okay.

Example:

const std::string& operator[](size_t pIndex) const
{
    // some logic
    return mData[pIndex];
}

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

}

Normally it would all be on one line.

GMan
+1 for the example code.
Tronic