Thread: error: '____' does not have class type

  1. #1
    Registered User
    Join Date
    Sep 2016
    Posts
    21

    error: '____' does not have class type

    I am trying to make a graph but when I am compiling my code I get the error mentioned in the title, and I can't figure out what the problem is. This is my code so far:

    Header:
    Code:
    #include <iostream>#include <string>
    #include <vector>
    #include <cstdlib>
    
    
    class Node{
        std::vector<Node*> neighbours;
        std::string        name;
    
    
        public:
            Node(){};
            ~Node(){};
    
    
            std::string node_getName(void){return name;}
            void        node_setName(std::string p_name){name = p_name;}
            std::vector<Node*>* node_getNeighbours(void){return &neighbours;}
    };
    
    
    class Graph{
        std::vector<Node*> nodes;
    
    
        public:
            Graph(){};
            ~Graph(){};
    
    
            std::vector<Node*>* graph_getNodes(void){return &nodes;}
            unsigned int        graph_getNbrNodes(void){return nodes.size();}
    
    
            void  graph_insertNode(std::string p_name);
            void  graph_insertEdge(Node* p_node1, Node* p_node2);
            Node* graph_chooseNode(std::string p_name);
    };
    Source:

    Code:
    #include "graph.h"
    
    void Graph::graph_insertNode(std::string p_name){
    
    
        std::vector<Node*>* graphNodes = graph_getNodes();
        unsigned int nbrNodes = graph_getNbrNodes();
    
    
        for (int i = 0; i < nbrNodes; i++){
            if (!p_name.compare(graphNodes->at(i)->node_getName())){
                return;
            }
        }
    
    
        Node newNode;
        newNode.node_setName(p_name);
        graphNodes->push_back(&newNode);
    }
    
    
    void Graph::graph_insertEdge(Node* p_node1, Node* p_node2){
    
    
        p_node1->node_getNeighbours.push_back(p_node2);
        p_node2->node_getNeighbours.push_back(p_node1);
    }
    
    
    Node* Graph::graph_chooseNode(std::string p_name){
    
    
        std::vector<Node*>* graphNodes = graph_getNodes();
        unsigned int nbrNodes = graph_getNbrNodes();
    
    
        for (int i = 0; i < nbrNodes; i++){
            if (!p_name.compare(graphNodes->at(i)->node_getName())){
                return graphNodes->at(i);
            }
        }
    }
    This is the error I get:
    error: '____' does not have class type-screenshot-2017-03-03-15-55-21-png

    Anyone understanding what's wrong?

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    You're returning a pointer to a vector (why isn't it a reference?)
    Also, node_getNeighbours is a function as well, so you need to make it a function call.

    So
    p_node1->node_getNeighbours()->push_back(p_node2);
    p_node2->node_getNeighbours()->push_back(p_node1);
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Your method-naming scheme is more like what someone would do in C, prefixing the functions with "node_" or "graph_". That doesn't make sense in C++. It's just noise and extra typing.

    Anyway, node_getNeighbours (which should just be called getNeighbours) returns a pointer so you need to use pointer->method not class.method.

  4. #4
    Registered User
    Join Date
    Sep 2016
    Posts
    21
    I am actually a C programmer trying to transition to C++, I guess you saw that But thank you a lot for the help!

  5. #5
    Registered User
    Join Date
    Sep 2016
    Posts
    21
    How does the scoping of objects work? Is it the same as any other variable? Right now I am not allocating anything from the functions. Should I do that?

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    Scope works exactly as normal.

    So for example, this is wrong.
    Code:
        Node newNode;
        newNode.node_setName(p_name);
        graphNodes->push_back(&newNode);
    You're storing a pointer to a local variable.

    You need to allocate a new one each time.
    Code:
        Node *newNode = new Node;
        newNode->node_setName(p_name);
        graphNodes->push_back(newNode);
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  7. #7
    Registered User
    Join Date
    Sep 2016
    Posts
    21
    So will I be unable to use std::string all together? I don't see why it's so good if it can't be allocated. Or is there a way to allocate a std::string so that it won't disappear after function returns?

  8. #8
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Salem never said anything about std::string. The way you are using std::string is okay. Look at his example again. The problem in your code in post 1 is that you are storing the address of a local (stack) variable in your graph. You need to allocate it on the heap with new.

    BTW, it doesn't make sense that you make nbrNodes an unsigned int and then make the index variable of the for loop an int. They should match. Your compiler should give you a warning about that. And we would usually use a size_t instead of an unsigned int, as size_t is more likely to match std::vector<...>::size_type, the actual return value of vector's size() method.

    Also, instead of this:
    Code:
    if (!p_name.compare(graphNodes->at(i)->node_getName()))
    we would normally say
    Code:
    if (p_name == graphNodes->at(i)->getName())
    This is C++, after all!

  9. #9
    Registered User
    Join Date
    Sep 2016
    Posts
    21
    I am trying, but there is so much more than in C I have made some progress and changed some pointers to references. They really seem good. I had done something wrong when I tried to allocate a std::string, works now though. I did however forget to put an asterix when trying to compare two std::string and I got five whole screens of a compiler error. What in the world is the point of that? Another question I have: Are iterators just kinda like pointers?

    This is my final code. Are there anything you C++ oldies really think is wrong or really bad C++ style?

    Header:
    Code:
    class Node{    std::vector<Node*> neighbours;
        std::string*       name;
    
    
        public:
            Node(){};
            ~Node(){};
    
    
            std::string*&       getName(void){return name;}
            void                setName(std::string p_name){*name = p_name;}
            std::vector<Node*>& getNeighbours(void){return neighbours;}
    };
    
    
    class Graph{
        std::vector<Node*> nodes;
    
    
        public:
            Graph(){}
            ~Graph();
    
    
            std::vector<Node*>& getNodes(void){return nodes;}
            unsigned int        getNbrNodes(void){return nodes.size();}
    
    
            void  insertNode(std::string p_name);
            void  insertEdge(Node* p_node1, Node* p_node2);
            void  deleteNode(std::string p_name);
            Node* chooseNode(std::string p_name);
    };
    Source:
    Code:
    #include "graph.h"
    
    void Graph::insertNode(std::string p_name){
    
    
        std::vector<Node*>& graphNodes = getNodes();
        unsigned int nbrNodes = getNbrNodes();
    
    
        for (unsigned int i = 0; i < nbrNodes; i++){
            if (p_name == *graphNodes.at(i)->getName()){
                std::cerr<< p_name<< " already exist"<< std::endl;
                return;
            }
        }
    
    
        Node* newNode = new Node;
        newNode->getName() = new std::string;
        newNode->setName(p_name);
        graphNodes.push_back(newNode);
    }
    
    
    void Graph::insertEdge(Node* p_node1, Node* p_node2){
    
    
        p_node1->getNeighbours().push_back(p_node2);
        p_node2->getNeighbours().push_back(p_node1);
    }
    
    
    Node* Graph::chooseNode(std::string p_name){
    
    
        std::vector<Node*>& graphNodes = getNodes();
        unsigned int nbrNodes = getNbrNodes();
    
    
        for (unsigned int i = 0; i < nbrNodes; i++){
            if (p_name == *graphNodes.at(i)->getName()){
                return graphNodes.at(i);
            }
        }
        std::cerr<< p_name<< " doesn't exist"<< std::endl;
    
    
        return nullptr;
    }
    
    
    void Graph::deleteNode(std::string p_name){
    
    
        std::vector<Node*>& graphNodes = getNodes();
        unsigned int nbrNodes = getNbrNodes();
    
    
        for (unsigned int i = 0; i < nbrNodes; i++){
            if (p_name == *graphNodes.at(i)->getName()){
                delete graphNodes.at(i)->getName();
                delete graphNodes.at(i);
                graphNodes.erase(graphNodes.begin() + i);
                break;
            }
        }
    }
    
    
    Graph::~Graph(){
    
    
        std::vector<Node*>& graphNodes = getNodes();
        unsigned int nbrNodes = getNbrNodes();
    
    
        for (unsigned int i = 0; i < nbrNodes; i++){
            delete graphNodes.at(i)->getName();
            delete graphNodes.at(i);
        }
    }

  10. #10
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    > std::string* name;
    There is absolutely no need for this to be a pointer.

    Just make it a regular object and do this
    Code:
    void                setName(std::string p_name){name = p_name;}
    And delete these two lines from their respective functions.
    Code:
        newNode->getName() = new std::string;
        delete graphNodes.at(i)->getName();
    C++ will do a lot of grunt work memory management for you, so let it do it.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  11. #11
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Code:
    #include <iostream>
    #include <string>
    #include <vector>
    
    using std::string;
    class Node;
    typedef std::vector<Node*> NodeVec;
    
    class Node{
        string name;
        NodeVec neighbours;
    public:
        Node(string name) : name(name) {}
        string& getName(void) { return name; }
        void addNeighbour(Node* node) { neighbours.push_back(node); }
        void print();
    };
    
    void Node::print() {
        std::cout << name << '\n';
        for (size_t i = 0; i < neighbours.size(); i++)
            std::cout << '\t' << neighbours[i]->getName() << '\n';
    }
    
    class Graph{
        NodeVec nodes;
    public:
        ~Graph();
        size_t size(void) { return nodes.size(); }
        void insertNode(string name);
        void insertEdge(Node* node1, Node* node2);
        void deleteNode(string name);
        Node* getNode(string name);
        void print();
    };
    
    void Graph::insertNode(string name) {
        for (size_t i = 0; i < nodes.size(); i++)
            if (name == nodes[i]->getName()) {
                std::cerr << name << " already exists\n";
                return;
            }
        nodes.push_back(new Node(name));
    }
    
    void Graph::insertEdge(Node* node1, Node* node2) {
        node1->addNeighbour(node2);
        node2->addNeighbour(node1);
    }
    
    Node* Graph::getNode(string name){
        for (size_t i = 0; i < nodes.size(); i++)
            if (name == nodes[i]->getName())
                return nodes[i];
        std::cerr << name << " doesn't exist\n";
        return nullptr;
    }
    
    void Graph::deleteNode(string name) {
        for (size_t i = 0; i < nodes.size(); i++) {
            if (name == nodes[i]->getName()) {
                delete nodes[i];
                nodes.erase(nodes.begin() + i);
                break;
            }
        }
    }
    
    Graph::~Graph() {
        for (size_t i = 0; i < nodes.size(); i++)
            delete nodes[i];
    }
    
    void Graph::print() {
        for (size_t i = 0; i < nodes.size(); i++)
            nodes[i]->print();
    }
    
    int main() {
        Graph g;
        g.insertNode("one");
        g.insertNode("two");
        g.insertNode("three");
        g.insertEdge(g.getNode("one"), g.getNode("two"));
        g.insertEdge(g.getNode("one"), g.getNode("three"));
        g.insertEdge(g.getNode("two"), g.getNode("three"));    
        g.print();
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Error - Does not have a class type
    By johngoodman in forum C++ Programming
    Replies: 13
    Last Post: 04-22-2013, 08:13 PM
  2. Replies: 2
    Last Post: 02-27-2013, 07:52 AM
  3. Replies: 5
    Last Post: 07-24-2012, 04:25 AM
  4. Replies: 3
    Last Post: 07-08-2008, 10:01 AM
  5. Error using string class type
    By matth in forum C++ Programming
    Replies: 4
    Last Post: 01-11-2006, 05:52 PM

Tags for this Thread