tags:

views:

251

answers:

5

As the topic says I'm very new to c++, but I have some experience with java. To start learning c++ I had the (not very original) idea of making a simple command line calculator. What I'm trying to do is store the numbers and operators in a binary tree.

#include <iostream>
using namespace std;

class Node
{
  bool leaf;
  double num;
  char oper;
  Node* pLNode;
  Node* pRNode;

public:

  Node(double n)
  {
    num = n;
    leaf = true;
    pLNode = 0;
    pRNode = 0;
  }

  Node(char o, Node lNode, Node rNode)
  {
    oper = o;
    pLNode = &lNode;
    pRNode = &rNode;
    leaf = false;
  }

  bool isLeaf()
  {
    return leaf;
  }

  double getNumber()
  {
    return num;
  }

  char getOperator()
  {
    return oper;
  }

  Node* getLeftNodePointer()
  {
    return pLNode;
  }

  Node* getRightNodePointer()
  {
    return pRNode;
  }

  //debug function
  void dump()
  {
    cout << endl << "**** Node Dump ****" << endl;
    cout << "oper: " << oper << endl;
    cout << "num: " << num << endl;
    cout << "leaf: " << leaf << endl;
    cout << "*******************" << endl << endl;
  }

};

class CalcTree
{
  Node* pRootNode;
  Node* pCurrentNode;
public:

  Node* getRootNodePointer()
  {
    return pRootNode;
  }

  Node* getCurrentNodePointer()
  {
    return pCurrentNode;
  }

  void setRootNode(Node node)
  {
    pRootNode = &node;
  }

  void setCurrentNode(Node node)
  {
    pCurrentNode = &node;
  }

  double calculateTree()
  {
    return calculateTree(pRootNode);
  }

private:

  double calculateTree(Node* nodePointer)
  {
    if(nodePointer->isLeaf())
    {
      return nodePointer->getNumber();
    }
    else
    {
      Node* leftNodePointer = nodePointer->getLeftNodePointer();
      Node* rightNodePointer = nodePointer->getRightNodePointer();
      char oper = nodePointer->getOperator();

      if(oper == '+')
      {
    return calculateTree(leftNodePointer) + calculateTree(rightNodePointer);
      }
      else if(oper == '-')
      {
    return calculateTree(leftNodePointer) - calculateTree(rightNodePointer);
      } 
      else if(oper == '*')
      {
    return calculateTree(leftNodePointer) * calculateTree(rightNodePointer);
      }
      else if(oper == '/')
      {
    return calculateTree(leftNodePointer) / calculateTree(rightNodePointer);
      }
    }
  }
};

int main(int argc, char* argv[])
{
  CalcTree tree;
  tree.setRootNode(Node('+', Node(1), Node(534)));
  cout << tree.calculateTree() << endl;
  return 0;
}

I've got a couple of questions about this code:

  1. This compiles but does not do what's intended. It seems that after tree.setRootNode(Node('+', Node(1), Node(534))); in main, the rightnode is initialized properly but the leftnode isn't. Compiling and running this prints out 534 for me (gcc, freebsd). What is wrong here?

  2. It seems in c++ people prefer to define members of a class outside the class, like

    class A { public: void member(); };

    A :: member(){std::cout << "Hello world" << std::endl;}

    why is that?

  3. I'd very much like some pointers on c++ conventions (naming, indenting etc.)

  4. I'm used to coding java with eclipse. Atm I'm using emacs for learning c++. Can someone advise me on a good (free) c++ ide, or should I stfu and stick with emacs like a real man? :)

A: 

There are very different conventions for C++. Google some. There is no "official" convention. ;)

To your IDE question: I am using the CDT (C[/C++] Development Tools, Eclipse). There has been a first release for another Eclipse based C++ IDE: http://www.eclipse.org/linuxtools/ I am going to test it out these days. Sounds very good.

Also try out KDevelop if you are using KDE.

Lennart
A: 
2. It seems in c++ people prefer to define members of a class outside the 
class[..]

It's a matter of style. Mostly. We group the big bulky methods in a separate cpp file, and keep the small ones along with the header file. Declaring the method within the class declaration makes the function inline (which is a hint for the compiler to do, you guessed it -- inlining). This is something you may or may not want depending on the problem you want to solve.

3. I'd very much like some pointers on c++ conventions (naming, indenting etc.)

The standard library is a good reference. Start looking at the headers.

4. I'm used to coding java with eclipse.

Eclipse can be configured to use a C++ compiler. Go(ogle) for it, please. Why punish yourself twice now that you've taken to C++ ;-)

dirkgently
+5  A: 
  • First, I can only recommend to have a look at the book "Accelerated C++". It will jump-start you into STL, and C++ style, and can save you a year of bad experiences. (There is quite an amount of extraordinary well written literature on C++ out there, if you decide to go deeper).

  • C++ does not use automatic memory management on the heap. You are storing pointers to temporaries. Your program is incorrect as it tries to access destructed objects. Like it or not, you'll have to learn on object lifetime first. You can simplify a good part of this in simple cases by using value semantics (not storing pointers, but storing a copy of the object).

  • Eclipse/CDT is reported to be quite OK on linux. On Windows you'll do easier with Microsoft Visual C++ Express Edition. When you've gotten into the basics, switching later will be no problem for you.

  • Defining members outside of the class itself is preferred as we usually split header and implementation files. In the header you try not to expose any unnecessary information, and also to reduce code-size, it's a simple matter of compile time. But for many modern programming techniques (like using template meta-programming) this cannot be used, so quite some C++ code moves in the direction of inline definitions.

gimpf
+1  A: 
  1. You're passing by value, not by reference when you say

    Node(char o, Node lNode, Node rNode)

It should be

Node(char o, Node &lNode, Node &rNode)

or better yet (for consistency with the rest of your code),

Node(char o, Node *lNode, Node *rNode)
  1. Compilation speed: The header (.h file) contains extra information not embedded in the .o files, so it must be recompiled by every other C++ file that includes it. Space: If you include method bodies, they are duplicated in every file that includes the .h file. This is in contrast to Java, where all of the relevant information is embedded in the .class file. C++ cannot do this because it is a much richer language. In particular, macros make it so that C++ will never be able to embed all the information in a .o file. Also, Turing-complete templates make it challenging to get rid of the .h / .cpp distinction.

  2. There are many conventions. The standard C++ library has one set, the standard C library has another, BSD and GNU each have their own, and Microsoft uses yet another. I personally like to be fairly close to Java when it comes to naming identifiers and indenting.

  3. Eclipse, NetBeans, KDevelop, vim, and emacs are all good options. If you're on Windows, Visual Studio is really nice.

Mr Fooz
+4  A: 
Johannes Schaub - litb
+1, not only for the code review, but especially for the link to this book guide. I didn't know that page on SO, it's really a nice collection.
gimpf
+1, Thanks for the code review and clarifying explanations!
Ramiel