2

I've been working with a lot of C and Java lately so I'm a bit confused coming back to C++ on why this is not allowed.

incomplete type is not allowed

#pragma once

class Expression
{
private:
    Expression power; // <--- incomplete type is not allowed
};

I believe the answer here is to change the line Expression power to Expression *power but I don't understand why that is. I can declare objects like vector<int> var without having to make them a pointer, but the second I have an object of the same type as the file it's being declared in, I need one? I've looked around but cannot find any tutorials/videos on a class making an object of itself.

Hatefiend
  • 3,416
  • 6
  • 33
  • 74
  • 11
    You can't embed a class in itself. Think twice: That causes infinite recursion. Use a pointer or better a smart pointer instead. – πάντα ῥεῖ Aug 31 '16 at 13:50
  • Aside from the infinite recursion problem, you cannot use an incomplete type to define a member of a class because the compiler cannot know how much space to reserve in class instances for that member. Because the type is incomplete, it cannot yet know how big the class is. – Cody Gray - on strike Aug 31 '16 at 13:52
  • rethink your design, there is no real problem that needs this as solution – 463035818_is_not_an_ai Aug 31 '16 at 13:53
  • I think the OP wants to do something similar to the pimpl idiom, though a bad way. – plasmacel Aug 31 '16 at 13:54
  • @πάνταῥεῖ ῥε If I use a pointer, will I then have to use `malloc` or `calloc` like in C to tell the compiler: "Hey, I want this pointer to point to an actual object now" ? – Hatefiend Aug 31 '16 at 13:54
  • @Hatefiend Look at: https://en.wikipedia.org/wiki/Opaque_pointer#C.2B.2B – plasmacel Aug 31 '16 at 13:55
  • @tobi303 There is though. What I'm trying to do is have an object type that represents a mathematical expression, such as `2x + 4`. The issue is mathematical expressions can be raised to powers such as `(2x + 4)^8` Mathematical expressions can be raised to expressions as well, such as `(2x + 4)^(x^2 - 3x + 1)`. This is why I have an `Expression` variable to represent a possible `power` or `exponent`. – Hatefiend Aug 31 '16 at 13:56
  • 3
    @Hatefiend _" will I then have to use `malloc` or `calloc`"_ For heavens sake no! For classes you need `new` and `delete`, but as mentioned use e.g. a `std::unique_ptr` that will release you from doing that consistenly your own. – πάντα ῥεῖ Aug 31 '16 at 13:58
  • @Hatefiend If you say "There is though", then you didnt understand, what this construct means. The difference is "expressions **can** be raised to.." but in your design every `Expression` is composed of another `Expression` which is not the appropriate model for " I have an Expression variable to represent **a possible** power or..". In your current design the power isnt optional or just "possible", but it has to be there and further itself has to have a power and so on ad infinitum – 463035818_is_not_an_ai Aug 31 '16 at 14:01
  • @tobi303 I see what you mean, but I thought since in my header declaration, `Expression power` is null until I create it, and thus there is no recursion. Meaning like, I tell the compiler "Hey, it's possible for this class to have an `Expression` variable, but I'll let you know when I'm ready to initialize it. – Hatefiend Aug 31 '16 at 14:07
  • it gets initialized when you call the constructor, it cannot be null (unless you make it a pointer) – 463035818_is_not_an_ai Aug 31 '16 at 14:11
  • @Hatefiend I'd recommend picking up an [introductory book](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) on C++. – TartanLlama Aug 31 '16 at 14:18
  • @Hatefiend _"`Expression power` is null "_ Nope! C++ isn't Java. This member cannot ever be `null`. – πάντα ῥεῖ Aug 31 '16 at 14:42
  • @πάντα ῥεῖ If I want that functionality, I must make the variable a pointer? – Hatefiend Aug 31 '16 at 14:44
  • @Hatefiend Yes. Use the `std::unique_ptr` (or `std::shared_ptr`) as mentioned. – πάντα ῥεῖ Aug 31 '16 at 14:46
  • @πάνταῥεῖ I've never seen that before. How does that work vs. using `Expression *myPtr` ? – Hatefiend Aug 31 '16 at 14:58
  • @Hatefiend You can read the details and see examples in the [reference documentation](http://en.cppreference.com/w/cpp/memory). – πάντα ῥεῖ Aug 31 '16 at 15:12

1 Answers1

3

If you put an instance of a class inside itself, if you notice, you are creating recursion, since every instance has its own Expression power, and this goes on forever. If you have a pointer though, you can control this infinite recursion, since at any time you can set power to nullptr, (or NULL/0, pre C++11), to end the recursion.

Arnav Borborah
  • 11,357
  • 8
  • 43
  • 88
  • I see. I wonder then, why would a line like this work totally okay in Java but in C++ it causes so many problems? – Hatefiend Aug 31 '16 at 14:01
  • 3
    The same thing would happen in Java, as you can see here: http://stackoverflow.com/questions/8023319/declaring-an-instance-of-a-class-inside-that-class The only difference is that the compiler would never know – Arnav Borborah Aug 31 '16 at 14:10
  • Yes but that user is doing `Animal object1 = new Animal();` in the declaration for the `Animal` class which here I am essentially typing `Animal object1;` without initializing it. That's kind of what I'm not getting. – Hatefiend Aug 31 '16 at 14:14
  • The point of that link was differentiation. The code in the link would cause recursion, but in your case, the code is fine, since the ctor is not called for the class, almost like a pointer – Arnav Borborah Aug 31 '16 at 14:30
  • @Hatefiend, to more precisely answer, in Java, you are *always* declaring references (pointers) to class types, never values. In C++ you can do either, and references or pointers are explicitly annotated as such. – N8allan Jun 02 '21 at 21:55