views:

79

answers:

4

I have two classes which depend on each other. I've solved this problem before but I can not for the life of me remember how to fix this. My simplified code is this:

struct MenuOption{
  string Text;
  int Choice;
  bool UseSubMenu;
  Menu SubMenu;
};

class Menu{
public:
  Menu(MenuOption optionlist[],int optioncount);
};
A: 

You need to use the pointers instead of objects. I beleive in this case SubMenu needs to be Menu*

EDIT

Actually as others mentioned forward declaration is also needed. But with forward declarations you can just define pointer/reference but you can not create a object. When you try to create an object the compiler needs to know what is the sizeof of the object, which is not available (even if you forward declare). With forward declaration you are telling the compiler that Menu is of type class and you are stroring a pointer to Menu type object. Think about it, having an instance one into another will be infinite recusrion.

Naveen
I don't understand why I would need to use pointers in this case. Care to explain? Isn't forward declaring enough? (aside from the fact that my class hasn't actually "learned" pointers)
Earlz
When a structure is defined, the compiler needs to know the the size of the structure. When a forward declaration is done, it tells the compiler that a class exists but not its size. This means that when the compiler tries to determine the size of MenuOption, it cannot deduce it because it doesn't know the size of Menu and Menu's size only gets determined *after* MenuOption. But if it's a pointer to a class, compiler doesn't need to know the size of the class, because it's just a pointer and pointers have fixed size (depending on the CPU architecture).
Vite Falcon
+2  A: 
  • Use forward declarations

I.e.:

// Forward declaration to assure A of B's existence.
class B;

class A { // uses B
  B* b;
};

class B { // uses A
  A* a;
};
  • Use pointers and not object instances: because the compiler needs to know how much space to allocate to the members of a class. Having an object instance there is therefore not going to work because the compiler doesn't know its size without seeing the full declaration of its class. Pointers, however, all have the same size which is known to the compiler without looking at anything extra.
Eli Bendersky
Ah. That makes sense. I completely forgot about the recursive infinite size structure that'd make.
Earlz
A: 
class Menu;
struct MenuOption{
  string Text;
  int Choice;
  bool UseSubMenu;
  Menu* SubMenu;
};

class Menu{
public:
  Menu(MenuOption optionlist[],int optioncount);
};

Basically, you 'forward declare' the class Menu and then use a pointer to Menu as the SubMenu.

Vite Falcon
+1  A: 

Use forward declarations

struct MenuOption;

class Menu{
public:
  Menu(MenuOption optionlist[],int optioncount);
};

struct MenuOption {
  string Text;
  int Choice;
  bool UseSubMenu;
  Menu SubMenu;
};

You don't need to make any data member a pointer. There is no "recursive infinite size" in the above code snippet.

Independent of this, it still looks like a good idea to make that SubMenu a pointer. Because it does not seem to be required to have a submenu, is it? So you should use a pointer since otherwise that member will always be a menu and needs to be initialized. A pointer can be left uninitialized or as a null pointer. You might also want to use boost::optional<> instead

struct MenuOption {
  string Text;
  int Choice;
  boost::optional<Menu> SubMenu;
};
Johannes Schaub - litb