简体   繁体   中英

C++: How to implement private helper function that requires access to protected members of a class without altering header file?

I'm trying to declare and use a generic helper function to do recursion.
The issue is, I cannot touch the default header file .
We are allowed to linked the default header file and add implementation to another header file, however, I don't know how to add more functions to the class Node declared in the default without the redefinition error.
Note : there are getters for the Node class but no setters, same for Tree.
Note2 : We can only linked the default header file, cannot add other headers files.

What I want if I can declare the helper:

template <class T>
void Tree<T>::add(const T &x){
    if(root){
        root->insertNode(x);
    } else{
        root = new Node<T>(x);
    }
}

template <class T>
void Node::insertNode(T const &x){
    if(x < value){
        if(left){
            left->insertNode(x);
        } else{
            left = new Node<T>(x);
        }
    } else if(x > value){
        if(right){
            right->insertNode(x);
        } else{
            right = new Node<T>(x);
        }
    }
}

Which leads to this error:

Out-of-line definition of 'insertNode' does not match any declaration in 'Node<T>'

Because the helper function wasn't defined in the default header.
I can't declare Node::insertNode without changing the default header.

As you can see, the helper needs access to protected members of Node (data, left, right).
I tried passing (Node*) as additional parameter to the helper as a free function, but then I don't know how to set left and right with just getters (there are no setter functions in the header).
So I can't set it to a free function without declaring it as friend in the header, which again, I can't touch.

What can I do? Suggestion?


Edit:
Following suggestion of @darune, I tried passing in reference as param:

template <class Base>
void insertNode(const Base &item, Node<T>& node){
    if(item < node->data){
        if(node->left){
            insertNode(item, node->left);
        } else{
            node->left = new BSTNode<Base>(item);
        }
    } else if(node->data > item){
        if(node->right){
            insertNode(item, node->right);
        } else{
            node->right = new BSTNode<Base>(item);
        }
    }
}

But then I get:

error: base operand of '->' has non-pointer type 'Node<int>'
if(item < node->data)

If I try to change the -> to . (like node.data), then it just says:

Node<T>::data is protected within this context

Edit2:
Using template argument as reference param (not sure if correct):

template <class T, class S>
void insertNode(const Base &item, S& node){
    if(item < node->data){
        if(node->left){
            insertNode(item, node->left);
        } else{
            node->left = new BSTNode<Base>(item);
        }
    } else if(node->data > item){
        if(node->right){
            insertNode(item, node->right);
        } else{
            node->right = new BSTNode<Base>(item);
        }
    }
}

Gives me the same issue as above:

error: base operand of '->' has non-pointer type 'Node<int>'
if(item < node->data)

According to the language rules you cannot add a member helper function without modifying the header file.

What you could do:

  • Either create standalone helper function (non-member) and work with the public interface of Node

or

  • Create a wrapper, for ex. class NodeWrapper : public Node and work with the wrapper class:

     template <typename T> class NodeWrapper : public Node<T> { void insertNode(const T& x) { ... rest of the code ... ... you can access protected member of Node here, but not the private ones } }

You could just pass a reference (or a pointer) to the protected/private member into the function that needs to work on it. That way you still uphold all language and design principles. Also an added benefit is improved encapsulation.

Something like:

void insertNode(const auto& x, auto& left, auto& right){

Also, try to avoid using raw pointers in c++ (unless you have a good reason to). It's the modern way. Passing a raw pointer to a function is the only place where it still makes sense, since means it is optional (and hence should be reflected inside the function).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM