10

I am new to C++ and have a question:

Compare following code:

class Node { 
public:
    int data;
    Node* x;
};

and

class Node { 
public:
    int data;
    Node x;
};

I know the second part of code can't pass compile. But I want to know the reason.

Is it related to memory allocation or just syntax regulation?

I would be appreciate if someone can solve my question.

Oh2
  • 127
  • 2
  • 9
  • The compiler doesn't have to know enything on Node to be able to manage a pointer to a node. – Caduchon Oct 23 '14 at 13:00
  • It is at least partially related to memory allocation, because the size of `Node` instance will go to infinity because of recursion. Each Instance will contain all the variables of `Node` plus another instance of `Node`, which will contain one more Instance and so on. In the end the construct cannot be allocated because its size is infinite. – antipattern Oct 23 '14 at 13:04
  • But how about a pointer? I think the first case can pass compile and work correctly. – Oh2 Oct 23 '14 at 13:08
  • @Oh2 Yes it can. (By the way, if you know Java: it's more or less equivalent to the Java version `class Node { public int data; public Node x; }`, as in Java variables of a class type are *implicitly* just pointers.) – leemes Oct 23 '14 at 13:14

5 Answers5

19

If you could, then a Node would contain a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node, which contains a Node... and so on until the universe is full of Nodes and implodes.

molbdnilo
  • 64,751
  • 3
  • 43
  • 82
12

The code in your second fragment cannot compile, because the class Node is not completely defined at the point where you declare its data member x of Node type.

For the sake of understanding, imagine if it could compile, it would lead to some sort of "infinite recursion structure", that would take an infinite amount of memory. Here's the hypothetical layout of such a class object:

{
  data: int
  x: Node
  {
    data: int
    x: Node
    {
      data: int
      x: Node
      {
        ...
      }
    }
  }
}

The first case works because you do not need a class to be fully defined in order to declare a pointer to it.
I find that thinking of "fully defined" as "the compiler knows how big this class is" helps to reason about problems like this: the compiler needs to know how big a class is to declare an instance of it, but not to declare a pointer to it, which has the same size regardless of the class.

Martin J.
  • 5,028
  • 4
  • 24
  • 41
7

It's more related to basic logic. In order for Node to contain an object of the same size as itself, and something else, it would have to be larger than itself, or infinite in size.

The language also prevents it since the type is incomplete within its own definition (so you can't even have the degenerate case of an otherwise empty class containing itself). But that's rather incidental to the more fundamental logical impossibility.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
0

The compiler needs to know the complete type of A when it founds it inside class A. Because A is incomplete, it cannot determine its size, it cannot determine how much space the member variable a is going to take, therefore it will not compile it.

Laura Maftei
  • 1,863
  • 1
  • 15
  • 25
-2

To fix such a problem you could also give forward declaration a try. But the problem lies in what Martin J Already stated.

class Node;

class Node { 
public:
    int data;
    Node* x;
};

bear in mind this is not tested

Blaatz0r
  • 1,205
  • 1
  • 12
  • 24
  • 2
    That is not necessary, at the time you declare a pointer to `Node`, the compiler already knows it is the name of a class, even without forward declaration. – Dettorer Oct 23 '14 at 13:21
  • Don't know if you've been downing my post. If so the reason is why? I've stated that it isn't tested. – Blaatz0r Oct 24 '14 at 09:24
  • I did, because of what I said (your answer, while not harmful, doesn't help and adds nothing to the existing answers) and partly because of the "not tested" :D. You should not give an answer when you don't know if it works (especially for such a short and easy to test one). – Dettorer Oct 24 '14 at 09:34
  • 1
    I'm sorry, I really didn't mean to be rude. The reasons I downvoted your answer is because it does not answer the question and won't help any future reader (forward declaration is completely useless in OP's problem *and* in your example). Your example works only because of the pointer, the forward declaration can be removed. Again I'm really sorry if I offended you, this was absolutely not the point of this simple downvote. – Dettorer Oct 27 '14 at 09:32