Thread: Confused on Class scopes

  1. #1
    Registered User
    Join Date
    Apr 2008
    Posts
    610

    Confused on Class scopes

    Please help me resolve my class scopes
    Code:
    // First.h
    #include "Second.h"
    class First
    {
    
    };
    Code:
    // Second.h
    #include "Third.h"
    class Second
    {
    
    };
    Code:
    // Third.h
    #include "Fourth.h"
    class Third
    {
    
    };
    Code:
    // Fourth.h
    #include "First.h"
    class Fourth
    {
    // Got an error here because First includes Second, which includes third, which includes 'this'
    };
    I need to use class First in fourth, how do i do that?

  2. #2
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,817
    You can start with some inclusion guards:
    Code:
    #ifndef FIRST_H
    #define FIRST_H
    // First.h
    #include "Second.h"
    class First
    {
    
    };
    #endif
    Code:
    #ifndef SECOND_H
    #define SECOND_H
    // Second.h
    #include "Third.h"
    class Second
    {
    
    };
    #endif
    Code:
    #ifndef THIRD_H
    #define THIRD_H
    // Third.h
    #include "Fourth.h"
    class Third
    {
    
    };
    #endif
    Code:
    #ifndef FOURTH_H
    #define FOURTH_H
    // Fourth.h
    #include "First.h"
    class Fourth
    {
    // Got an error here because First includes Second, which includes third, which includes 'this'
    };
    #endif
    That might be what you're seeing.
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

  3. #3
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    You need include guards. Then you won't recursively include things.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  4. #4
    The larch
    Join Date
    May 2006
    Posts
    3,573
    I need to use class First in fourth, how do i do that?
    You have a cyclic dependency that means you'll need to break it with forward declarations.

    Generally any header that doesn't need to know the full definition of a type shouldn't include that header, but forward-declare the type in question. Implementation files (*.cpp) generally need to know the full definition of the forward-declared types, so this is where you include most headers.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  5. #5
    Registered User Stonehambey's Avatar
    Join Date
    Jan 2008
    Location
    Kent, UK
    Posts
    118
    Just a quick question. Hopefully this isn't hijacking the thread too much.

    When is it cool to use "#define"?

    We need it for inclusion guards as seen here, however we are told not to use it to define constants, and to instead use the 'const' keyword instead.

    Why is one use outdated and the other not? Are they different somehow?

  6. #6
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by Stonehambey View Post
    Just a quick question. Hopefully this isn't hijacking the thread too much.

    When is it cool to use "#define"?

    We need it for inclusion guards as seen here, however we are told not to use it to define constants, and to instead use the 'const' keyword instead.

    Why is one use outdated and the other not? Are they different somehow?
    It's acceptable to use #define for things that need the preprocessor to resolve the problem. In this case, you CAN NOT use const int, because that requires the compiler, and by that time, it's too late to not have a second copy of "first.h" content in the compiler input.

    For most other purposes, const is a better idea.

    For plain and simple number constants, #define works OK, with the only drawback that the debugger can't tell you the value of X with#define X 7, whilst a const int x = 7, the debugger should be able to tell you that x = 7.

    Edit: Perhaps a moderator can split this off, as it's pretty unrelated to the original thread.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  7. #7
    Registered User Stonehambey's Avatar
    Join Date
    Jan 2008
    Location
    Kent, UK
    Posts
    118
    Cheers

  8. #8
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> #define works OK, with the only drawback that the debugger can't tell you the value of X
    That's not the only drawback. #defines don't follow type or scope rules.

  9. #9
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> You have a cyclic dependency that means you'll need to break it with forward declarations.
    For example, you can generally forward declarate First in Fourth.h if First is not a member of Fourth and you don't call any member functions of First from inside the header. If you're using a pointer or reference to First inside Fourth.h then a forward declaration should be fine.

    Note that it is impossible for each class to hold a member of the previous one in the cycle, because then you'd have an infinitely recursive nesting of objects, so somewhere it should be possible to break the cycle with a forward declaration if not everywhere.

  10. #10
    Registered User
    Join Date
    Apr 2008
    Posts
    610
    Here's my problem

    Code:
    #ifndef MENUCONTEXT_H
    #define MENUCONTEXT_H
    
    #include "FleetMenu.h"
    
    // Class MenuContext
    class MenuContext 
    {
    public:
    	bool fquit;
    	
    	FleetMenu *menuPrt;  // NB ** Errors below are related to this line
    
    	MenuContext(FleetMenu *m) : fquit(false), menuPtr = m {}
    	~MenuContext() {};
    };
    typedef void (*MenuFunc)(MenuContext &ctxt);
    
    #endif
    Code:
    #ifndef FLEETMENU_H
    #define FLEETMENU_H
    
    #include "Menu.h"
    
    
    class FleetMenu
    {
    public:
    
    	FleetMenu();
    	void RunFleet();
    
    	// Menu functions
    	static void Exit(MenuContext &ctxt);
    
    private:
    
    	typedef vector<Car> CarFleet;
    	typedef CarFleet::iterator FleetIterator;
    
    private:
    	CarFleet fleet; 
    };
    
    #endif
    Code:
     // Class menu
    #ifndef MENU_H
    #define MENU_H
    
    #include "MenuItem.h"
    
    class Menu 
    {
    private:
    	struct MenuNode {
    		MenuNode *next;
    		MenuItem *item;
    	};
    
    	MenuNode *head;
    	MenuNode *tail;
    
    public:
    	Menu();
    	~Menu();
    
    	void addMenu(std::string s, char c, MenuFunc f);
    	void choose(MenuContext &ctxt);
    };
    
    #endif
    Code:
    // Class: Menuitem
    #ifndef MENUITEM_H
    #define MENUITEM_H
    
    #include "MenuContext.h"
    
    using namespace std;
    
    class MenuItem 
    {
    private:
    	std::string	descr;
    	char        choice;
    	MenuFunc    func;
    
    public:
    	MenuItem(const std::string &s, char c, MenuFunc f);
    	~MenuItem();
    	void print();
    	std::string whiteSpace(int slenght, char space);
    	void doMenu(MenuContext &ctxt);
    	bool isChoice(char c);
    };
    
    #end
    Code:
    // Errors
    
    // : error C2143: syntax error : missing ';' before '*'
    // : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
    // : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
    // : error C2143: syntax error : missing ')' before '*'
    
    // etc
    Mostly these errors are linked to scope
    Last edited by csonx_p; 07-25-2008 at 02:59 AM.

  11. #11
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Ok, let's see what header needs to include which headers:

    Code:
    #ifndef MENUCONTEXT_H
    #define MENUCONTEXT_H
    
    #include "FleetMenu.h"
    
    // Class MenuContext
    class MenuContext 
    {
    public:
    	bool fquit;
    	
    	FleetMenu *menuPrt;  // NB ** Errors below are related to this line
    
    	MenuContext(FleetMenu *m) : fquit(false), menuPtr = m {}
    	~MenuContext() {};
    };
    typedef void (*MenuFunc)(MenuContext &ctxt);
    
    #endif
    If I'm not mistaken this header doesn't need the full definition of FleetMenu, because it only deals with pointers to FleetMenu. Hence you should be able to replace the inclusion with a forward declaration:
    Code:
    class FleetMenu;
    Similarly:
    "fleetmenu.h" - since FleetMenu contains an instance of CarFleet, you need to include the header where it is defined. MenuContext is referred to only as a reference, so a forward declaration should be enough. This header might also need to include <vector>.

    "menu.h" - probably needs to include the header where MenuFunc is typedeffed. MenuContext could be forward declared (but it is defined in the same header anyway).

    "menu_item.h" - needs to include <string> and "menu_context.h" for the typedef of MenuFunc.

    All in all:
    "menu_context.h" -> includes nothing
    "fleet_menu.h" -> includes <vector>, "car_fleet.h"(?)
    "menu.h" -> includes "menu_context.h"
    "menu_item.h" -> includes <string>, "menu_context.h"

    and there should be no more circular inclusions.

    In short, forward-declare what you can and include what you need in headers. If the full type is needed for implementation, include the respective header in the CPP-file (if it was only forward-declared in the header).
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  12. #12
    Registered User
    Join Date
    Apr 2008
    Posts
    610
    Quote Originally Posted by anon View Post
    All in all:
    "menu_context.h" -> includes nothing
    "fleet_menu.h" -> includes <vector>, "car_fleet.h"(?)
    "menu.h" -> includes "menu_context.h"
    "menu_item.h" -> includes <string>, "menu_context.h"

    and there should be no more circular inclusions.

    In short, forward-declare what you can and include what you need in headers. If the full type is needed for implementation, include the respective header in the CPP-file (if it was only forward-declared in the header).
    Hi Anon, Yes, i have do have Car, vector, string includes already... I did cut my code short to avoid too much code. But i now understand what "forward declaration" means...

    Thanx

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Creating a database
    By Shamino in forum Game Programming
    Replies: 19
    Last Post: 06-10-2007, 01:09 PM
  2. deriving classes
    By l2u in forum C++ Programming
    Replies: 12
    Last Post: 01-15-2007, 05:01 PM
  3. Replies: 3
    Last Post: 10-31-2005, 12:05 PM
  4. Warnings, warnings, warnings?
    By spentdome in forum C Programming
    Replies: 25
    Last Post: 05-27-2002, 06:49 PM
  5. class member access denied
    By chiqui in forum C++ Programming
    Replies: 2
    Last Post: 05-27-2002, 02:02 PM