Reference Question

Discussion in 'C++' started by news.tkdsoftware.com, Sep 24, 2004.

  1. I have the following test code. What I have a question about is in
    Func2Ref. In the pointer example, the last called method is actually the
    one whom allocated memory for the object and returns the pointer to the
    calling parent for it to be printed. In the reference example, the parent
    actually creates the object but in Func2Ref, I need that object to be a
    derived type. This is like how AST traversal occurs **hint**.

    Can someone offer some input on how I should do this if I choose to use
    &object reference instead of *object pointers??

    class CNode {
    public:
    CNode() { }
    virtual ~CNode() { }
    virtual void print(void) = 0;
    };

    class CChildNode : public CNode {
    public:
    CChildNode() { }
    virtual ~CChildNode() { }
    };

    class CBabyNode : public CChildNode {
    public:
    CBabyNode(int nVal) m_nVal(nVal) { }
    virtual ~CBabyNode() { }
    void print(void) { cout << m_nVal; }
    private:
    int m_nVal;
    };

    void Func2Ptr(CNode *node) {
    node = new CBabyNode(5);
    }
    void Func1Ptr(CNode *node) {
    Func2Ptr(node);
    }
    void Func2Ref(CNode &node) {
    // here I need to be able to change
    // CNode to a CBabyNode and be able
    // to have it print its value when
    // the main program calls print.
    }
    void Func1Ref(CNode &node) {
    Func2Ref(node);
    }

    int main(int argc, char* argv[]) {
    {
    // Do pointer test
    CNode *pNode = NULL;
    Func1Ptr(pNode);
    if(pNode != NULL) {
    pNode->print();
    delete pNode;
    }

    // Do Ref test
    CNode node;
    Func1Ref(node);
    node.print();

    return 0;
    }

    Thanks!
    --
    news.tkdsoftware.com, Sep 24, 2004
    #1
    1. Advertising

  2. news.tkdsoftware.com

    David Hilsee Guest

    "news.tkdsoftware.com" <> wrote in
    message news:...
    > I have the following test code. What I have a question about is in
    > Func2Ref. In the pointer example, the last called method is actually the
    > one whom allocated memory for the object and returns the pointer to the
    > calling parent for it to be printed. In the reference example, the parent
    > actually creates the object but in Func2Ref, I need that object to be a
    > derived type. This is like how AST traversal occurs **hint**.
    >
    > Can someone offer some input on how I should do this if I choose to use
    > &object reference instead of *object pointers??
    >
    > class CNode {
    > public:
    > CNode() { }
    > virtual ~CNode() { }
    > virtual void print(void) = 0;
    > };
    >
    > class CChildNode : public CNode {
    > public:
    > CChildNode() { }
    > virtual ~CChildNode() { }
    > };
    >
    > class CBabyNode : public CChildNode {
    > public:
    > CBabyNode(int nVal) m_nVal(nVal) { }
    > virtual ~CBabyNode() { }
    > void print(void) { cout << m_nVal; }
    > private:
    > int m_nVal;
    > };
    >
    > void Func2Ptr(CNode *node) {
    > node = new CBabyNode(5);
    > }


    That's going to leak memory. Perhaps you meant for Func2Ptr to take a
    reference to a pointer?

    > void Func1Ptr(CNode *node) {
    > Func2Ptr(node);
    > }
    > void Func2Ref(CNode &node) {
    > // here I need to be able to change
    > // CNode to a CBabyNode and be able
    > // to have it print its value when
    > // the main program calls print.
    > }

    <snip>

    Could you elaborate on this? References may not be reseated. This is
    explained in the FAQ (http://www.parashift.com/c -faq-lite) section 8
    (References), question 5 (How can you reseat a reference to make it refer to
    a different object?). It sounds like you are trying to do something that is
    impossible. What are you really trying to do?

    --
    David Hilsee
    David Hilsee, Sep 24, 2004
    #2
    1. Advertising

  3. "news.tkdsoftware.com" <> wrote in
    message news:...
    >I have the following test code. What I have a question about is in
    > Func2Ref.


    Actually you have a few misunderstandings. Chiefly that you don't understand
    how to return a value from a function.

    > In the pointer example, the last called method is actually the
    > one whom allocated memory for the object and returns the pointer to the
    > calling parent for it to be printed. In the reference example, the parent
    > actually creates the object but in Func2Ref, I need that object to be a
    > derived type. This is like how AST traversal occurs **hint**.
    >
    > Can someone offer some input on how I should do this if I choose to use
    > &object reference instead of *object pointers??
    >
    > class CNode {
    > public:
    > CNode() { }
    > virtual ~CNode() { }
    > virtual void print(void) = 0;
    > };
    >
    > class CChildNode : public CNode {
    > public:
    > CChildNode() { }
    > virtual ~CChildNode() { }
    > };
    >
    > class CBabyNode : public CChildNode {
    > public:
    > CBabyNode(int nVal) m_nVal(nVal) { }
    > virtual ~CBabyNode() { }
    > void print(void) { cout << m_nVal; }
    > private:
    > int m_nVal;
    > };
    >
    > void Func2Ptr(CNode *node) {
    > node = new CBabyNode(5);
    > }


    You mean

    CNode *Func2Ptr() {
    return new CBabyNode(5);
    }

    > void Func1Ptr(CNode *node) {
    > Func2Ptr(node);
    > }


    You mean

    CNode *Func1Ptr() {
    return Func2Ptr();
    }

    But this does exactly the same as the function above, so it hard to know
    what you intended.

    > void Func2Ref(CNode &node) {
    > // here I need to be able to change
    > // CNode to a CBabyNode and be able
    > // to have it print its value when
    > // the main program calls print.
    > }


    CNode cannot change to CBabyNode, it is impossible.

    > void Func1Ref(CNode &node) {
    > Func2Ref(node);
    > }
    >
    > int main(int argc, char* argv[]) {
    > {
    > // Do pointer test
    > CNode *pNode = NULL;
    > Func1Ptr(pNode);
    > if(pNode != NULL) {


    This will always be false, because the way you wrote Func1Ptr it did not
    return any value. Whith my correction it will at least return a value and
    pNode will be non NULL.

    > pNode->print();
    > delete pNode;
    > }
    >
    > // Do Ref test
    > CNode node;
    > Func1Ref(node);
    > node.print();
    >
    > return 0;
    > }
    >


    You are trying to do tree traversal, but you aren't coding anything like
    that. I think you have some serious misunderstanding about what you are
    doing. Unfortunately this makes it impossible to help because, whatever it
    is that you are trying to accomplish, you do not need to turn a CNode into a
    CBabyNode, so even if there was a way to do that it wouldn't help you. You
    are just asking the wrong questions.

    I would ask again but instead of asking about specific language questions,
    explain what it is that you are trying to do, and if you can, what it is
    that you don't understand.

    john
    John Harrison, Sep 24, 2004
    #3
  4. John -

    > You are trying to do tree traversal, but you aren't coding anything like
    > that. so even if there was a way to do that it wouldn't help you. You
    > are just asking the wrong questions.


    Yes, I am intending to generate/populate a tree. For example:

    PRINT 2+3*5

    would yield an AST tree so that I can traverse it using a visitor pattern
    to get the following output:


    5
    3
    *
    2
    +
    PRINT

    The goal of my prior post was to understand how I should construct my
    classes for the tree and how my functions could be written using reference
    variables as arguments instead of pointers to accomplish this.

    If someone could illustrate an example set of code, that would be great
    to help clear my misunderstandings.

    Thanks
    Chris
    news.tkdsoftware.com, Sep 24, 2004
    #4
  5. "news.tkdsoftware.com" <> wrote in
    message news:...
    > John -
    >
    >> You are trying to do tree traversal, but you aren't coding anything like
    >> that. so even if there was a way to do that it wouldn't help you. You
    >> are just asking the wrong questions.

    >
    > Yes, I am intending to generate/populate a tree. For example:
    >
    > PRINT 2+3*5
    >
    > would yield an AST tree so that I can traverse it using a visitor pattern
    > to get the following output:
    >
    >
    > 5
    > 3
    > *
    > 2
    > +
    > PRINT
    >
    > The goal of my prior post was to understand how I should construct my
    > classes for the tree and how my functions could be written using reference
    > variables as arguments instead of pointers to accomplish this.
    >
    > If someone could illustrate an example set of code, that would be great
    > to help clear my misunderstandings.
    >
    > Thanks
    > Chris
    >


    Do you actually understand the visitor pattern and it's motivation? Before
    you worry about using references not pointers I would write some code that
    actually implements the visitor pattern.

    I'm not a pattern expert but here my implementation using pointers. I hope
    this helps.

    #include <iostream>
    #include <string>

    class Node;

    class Visitor
    {
    public:
    virtual ~Visitor() {}
    virtual void visit_number(Node* node) = 0;
    virtual void visit_unary_func(Node* node) = 0;
    virtual void visit_binary_func(Node* node) = 0;
    };

    class Node
    {
    public:
    virtual ~Node() {}
    virtual void accept(Visitor* v) = 0;
    virtual void print(std::eek:stream& out) = 0;
    };

    class Number : public Node
    {
    public:
    Number(int n) : num(n) {}
    void accept(Visitor* v)
    {
    v->visit_number(this);
    }
    void print(std::eek:stream& out)
    {
    out << num << '\n';
    }
    private:
    int num;
    };

    class UnaryFunc : public Node
    {
    public:
    UnaryFunc(const std::string& n, Node* a) : name(n), arg(a) {}
    void accept(Visitor* v)
    {
    arg->accept(v);
    v->visit_unary_func(this);
    }
    void print(std::eek:stream& out)
    {
    out << name << '\n';
    }
    private:
    std::string name;
    Node* arg;
    };

    class BinaryFunc : public Node
    {
    public:
    BinaryFunc(const std::string& n, Node* a1, Node* a2) : name(n), arg1(a1) ,
    arg2(a2) {}
    void accept(Visitor* v)
    {
    arg1->accept(v);
    arg2->accept(v);
    v->visit_binary_func(this);
    }
    void print(std::eek:stream& out)
    {
    out << name << '\n';
    }
    private:
    std::string name;
    Node* arg1;
    Node* arg2;
    };

    class PrintVisitor : public Visitor
    {
    public:
    PrintVisitor(std::eek:stream& o) : out(o) {}
    virtual void visit_number(Node* node)
    {
    node->print(out);
    }
    virtual void visit_unary_func(Node* node)
    {
    node->print(out);
    }
    virtual void visit_binary_func(Node* node)
    {
    node->print(out);
    }
    private:
    std::eek:stream& out;
    };

    int main()
    {
    Number two(2);
    Number three(3);
    Number five(5);
    BinaryFunc times("*", &five, &three);
    BinaryFunc plus("+", &times, &two);
    UnaryFunc print("PRINT", &plus);
    PrintVisitor pv(std::cout);
    print.accept(&pv);
    }
    John Harrison, Sep 24, 2004
    #5
  6. The visitor patten you posted makes sense and did drive me in the right
    direction I do believe, see below.

    > Number two(2);
    > Number three(3);
    > Number five(5);
    > BinaryFunc times("*", &five, &three);
    > BinaryFunc plus("+", &times, &two);
    > UnaryFunc print("PRINT", &plus);
    > PrintVisitor pv(std::cout);
    > print.accept(&pv);
    > }


    I guess what I'm trying to understand is the best way for the parser to
    create the AST tree itself as it traverses the tokens from the lexer. See
    my code below. Comments are certainly welcome.

    As you can see, I pass the parent downward for tree population and have
    the function return the resultant node. I added logic in the classes
    you originally provided to take care of memory cleanup of the pointers
    that I am passing to those objects. Does what i have provided make
    logical sense?

    What would you suggest I do next?

    void CParser::parseProgram(void) {
    CProgram program; // class derived from CNode
    while(token.type != TOKEN_EOF) {
    CNode *statement = ParseStatement(program);
    // here I guess I need a way to
    // insert the returned statement
    // into my program class ??
    PrintVisitor pv(std::eek:stream);
    statement->accept(&pv);
    delete statement; }
    return program;
    }

    CNode* CParser::parseStatement(CNode &parent) {
    CNode *p = NULL;
    switch(token.type) {
    case OP_PRINT:
    p = new UnaryFunc("PRINT",ParseExpression(parent));
    break;
    default:
    throw CParserException(STATEMENT_EXPECTED);
    break;
    }
    return p;
    }

    CNode* CParser::parseExpression(CNode &parent) {
    CNode *p = ParseTerm(parent);
    while(token.type == OP_ADD || token.type == OP_SUB) {
    int op = token.type;
    GetNextToken();
    p = new BinaryFunc(op,p,ParseTerm(parent));
    }
    return p;
    }

    CNode* CParser::parseTerm(CExpr &parent) {
    CNode *p = ParseFactor(parent);
    while(token.type == OP_TIMES || token.type == OP_DIV) {
    int op = token.type
    GetNextToken();
    p = new BinaryFunc(op,p,ParseFactor(parent));
    }
    return p;
    }

    CNode* CParser::parseFactor(CExpr &parent) {
    CNode *p = NULL;
    switch(token.type) {
    case LPAREN:
    GetNextToken();
    p = ParseExpression(parent);
    if(token != RPAREN)
    throw CParserException(RPAREN_EXPECTED);
    break;
    case NUMBER:
    p = new Number(token);
    GetNextToken();
    break;
    default:
    throw CParserException(FACTOR_EXPECTED);
    break;
    }
    return p;
    }

    thanks
    chris
    ---
    news.tkdsoftware.com, Sep 24, 2004
    #6
  7. "news.tkdsoftware.com" <> wrote in
    message news:...
    > The visitor patten you posted makes sense and did drive me in the right
    > direction I do believe, see below.
    >
    >> Number two(2);
    >> Number three(3);
    >> Number five(5);
    >> BinaryFunc times("*", &five, &three);
    >> BinaryFunc plus("+", &times, &two);
    >> UnaryFunc print("PRINT", &plus);
    >> PrintVisitor pv(std::cout);
    >> print.accept(&pv);
    >> }

    >
    > I guess what I'm trying to understand is the best way for the parser to
    > create the AST tree itself as it traverses the tokens from the lexer. See
    > my code below. Comments are certainly welcome.


    Well that's a completely different problem.

    >
    > As you can see, I pass the parent downward for tree population and have
    > the function return the resultant node. I added logic in the classes
    > you originally provided to take care of memory cleanup of the pointers
    > that I am passing to those objects. Does what i have provided make
    > logical sense?
    >
    > What would you suggest I do next?
    >
    > void CParser::parseProgram(void) {
    > CProgram program; // class derived from CNode
    > while(token.type != TOKEN_EOF) {
    > CNode *statement = ParseStatement(program);
    > // here I guess I need a way to
    > // insert the returned statement
    > // into my program class ??


    Yes I think so.

    > PrintVisitor pv(std::eek:stream);
    > statement->accept(&pv);
    > delete statement; }
    > return program;
    > }
    >
    > CNode* CParser::parseStatement(CNode &parent) {
    > CNode *p = NULL;
    > switch(token.type) {
    > case OP_PRINT:
    > p = new UnaryFunc("PRINT",ParseExpression(parent));
    > break;
    > default:
    > throw CParserException(STATEMENT_EXPECTED);
    > break;
    > }
    > return p;
    > }
    >
    > CNode* CParser::parseExpression(CNode &parent) {
    > CNode *p = ParseTerm(parent);
    > while(token.type == OP_ADD || token.type == OP_SUB) {
    > int op = token.type;
    > GetNextToken();
    > p = new BinaryFunc(op,p,ParseTerm(parent));
    > }
    > return p;
    > }
    >
    > CNode* CParser::parseTerm(CExpr &parent) {
    > CNode *p = ParseFactor(parent);
    > while(token.type == OP_TIMES || token.type == OP_DIV) {
    > int op = token.type
    > GetNextToken();
    > p = new BinaryFunc(op,p,ParseFactor(parent));
    > }
    > return p;
    > }
    >
    > CNode* CParser::parseFactor(CExpr &parent) {
    > CNode *p = NULL;
    > switch(token.type) {
    > case LPAREN:
    > GetNextToken();
    > p = ParseExpression(parent);
    > if(token != RPAREN)
    > throw CParserException(RPAREN_EXPECTED);
    > break;
    > case NUMBER:
    > p = new Number(token);
    > GetNextToken();
    > break;
    > default:
    > throw CParserException(FACTOR_EXPECTED);
    > break;
    > }
    > return p;
    > }
    >


    It looks a lot better than the previous code. Looks like you are developing
    a recursive descent parser. I don't see why you are passing the parent down
    however, you never seem to do anything with it other than pass it along.

    john
    John Harrison, Sep 24, 2004
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Darren
    Replies:
    0
    Views:
    492
    Darren
    Oct 11, 2004
  2. Dude
    Replies:
    0
    Views:
    350
  3. ce
    Replies:
    1
    Views:
    2,984
  4. sam pal
    Replies:
    3
    Views:
    538
    E. Robert Tisdale
    Jul 16, 2003
  5. Craig Nicol
    Replies:
    2
    Views:
    466
    Craig Nicol
    May 10, 2004
Loading...

Share This Page