gowrath
gowrath

Reputation: 3224

C++ - Struct needs access to private instance variable of class

My C++ is a bit rusty so I was wondering if you could help me out. Basically, I have two structs and a class and the structs need access to the private instance variables of the class.

#ifndef TREE_H
#define TREE_H

#include <iostream>

struct Node {
    ...
    inline void addEdge(Edge* e);
};

inline void Node::addEdge(Edge* e) {
    char ch = inp[e->startIndex];
    edges[ch] = e;
}

struct Edge {
    Node* next = new Node();
    int startIndex = 0;
    friend std::ostream& operator<<(std::ostream& out, Edge e) {
        int index = inp.size() - e.startIndex + endIndex + 1;   // Here the edge needs access to the private members of the Tree class such as string inp, and int endIndex
        // ... do things with index
        return out;
    }
};


class Tree {
public:
    Tree();
    friend std::ostream& operator<<(std::ostream& out, Tree s);

private:
    Node* root = nullptr;
    int endIndex = 0;
    std::string inp;
    void foo();
    std::ostream& printTree(std::ostream& out, Node* curr, std::string append="");

};
#endif // TREE_H

So obviously the above code doesn't work. I was thinking I would move the structs inside the class. But then the << operator for Edge gives me an "invalid use of non-static data member 'endIndex'" error. One idea I'm sure will work is to pass a reference/pointer to endIndex as a member of Edge when I create the Edge but I was wondering what might be a better way to go about this.

Upvotes: 1

Views: 802

Answers (2)

gowrath
gowrath

Reputation: 3224

For anyone's future reference, I went with the pointer solution for now; seems to get the job done. My only doubt about this is whether endIndex in the Tree class needs to necessarily be on the stack (I think it does). Can anyone clarify?

#ifndef TREE_H
#define TREE_H

#include <iostream>

struct Node {
    ...
    inline void addEdge(Edge* e);
};

inline void Node::addEdge(Edge* e) {
    char ch = inp[e->startIndex];
    edges[ch] = e;
}

struct Edge {
    Edge(int start, int* endIndex) {        
        this->startIndex = start;
        this->endIndex = endIndex;
    }
    Node* next = new Node();
    int startIndex = 0;
    int* endIndex;
    friend std::ostream& operator<<(std::ostream& out, Edge e) {
        std::string value = inp.substr(e.startIndex,  *e.endIndex - e.startIndex + 1);
        out << "(---- " << value << "[" << e.startIndex << ", " << *e.endIndex << "] ---->)";
        return out;
    }
};


class Tree {
public:
    Tree();
    friend std::ostream& operator<<(std::ostream& out, Tree s);

private:
    Node* root = nullptr;
    int* endIndex = new int;   // am i correct in saying this needs to be on the stack? 
    std::string inp;
    void foo();
    std::ostream& printTree(std::ostream& out, Node* curr, std::string append="");

};
#endif // TREE_H

Upvotes: 0

mrAtari
mrAtari

Reputation: 650

I would propose to use the visitor pattern.

Here's a brief, incomplete example, to give you the idea:

class Tree
{
    Node _Node;
    std::list<Node> _Children;
public:
    ... // other stuff, like AddChild(), etc.

    void Traverse(Visitor visitor)
    {
        visitor.HandleNodeData(_Node.Data);
        traverseChildren(visitor);
    }
};

I would also consider to implement the Tree class as a template.

Upvotes: 1

Related Questions