Thread: Hiding constructors, exposing copy operations

  1. #1
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446

    Hiding constructors, exposing copy operations

    A MapHex class describes a map hexagon and its state. There's no functionality other than member functions that query the object state. Once constructed, a MapHex object is read-only. This object has some restrictions in the way it can be instantiated.

    A GameMap class is a container of Hexagons. This is the only object that can instantiate MapHex objects and store them in its state. It exposes its MapHex elements through observer member functions.

    In other words, a MapHex only makes sense as an element of GameMap. However MapHex still needs to expose its interface for non-related classes or functions to query it.

    The solution I found involves making MapHex constructor private and not disabling the compiler generated copy-constructor and assignment operator. Finally, GameMap is declared a friend of MapHex.

    Code:
    // gamemap.hpp
    
    class MapHex {
    public:
     
      friend class GameMap;
     
      ~MapHex() {}
     
      // observers
      unsigned int X()             const;
      unsigned int Y()             const;
      bool         hasRoad()       const;
      bool         hasRiver()      const;
      bool         hasSettlement() const;
      unsigned int countryID()     const;
      bool         active()        const;
      std::string  terrain()       const;
     
    private:
     
      MapHex(sqlite3_stmt *stmt);
     
      unsigned long hex_; /* packed data */
     
    };
     
    class GameMap {
    public:
     
          /* ... */
     
      const MapHex& getHexagon(const size_type X, const size_type Y) const;
     
    private:
     
               /* ... */
     
      std::vector<MapHex> map_;
    };
    I can make the copy constructor and assignment operator explicit for clarity. But the question is, do you advise this model? Is there a better way?
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  2. #2
    Anti-Poster
    Join Date
    Feb 2002
    Posts
    1,401
    What about something like this:
    Code:
    class MapHex {
    public:
    
    	~MapHex() {}
    
    	// observers
    	unsigned int X()             const;
    	unsigned int Y()             const;
    	bool         hasRoad()       const;
    	bool         hasRiver()      const;
    	bool         hasSettlement() const;
    	unsigned int countryID()     const;
    	bool         active()        const;
    	std::string  terrain()       const;
    
    	class GameMap {
    	public:
    
    		/* ... */
    
    		const MapHex& getHexagon(const size_type X, const size_type Y) const;
    
    	private:
    
    		/* ... */
    
    		std::vector<MapHex> map_;
    	};
    private:
    
    	MapHex(sqlite3_stmt *stmt);
    
    	unsigned long hex_; /* packed data */
    
    };
    Meh, maybe not. I'm not a huge fan of nested classes, but I do try to keep my friends down to a minimum.
    If I did your homework for you, then you might pass your class without learning how to write a program like this. Then you might graduate and get your degree without learning how to write a program like this. You might become a professional programmer without knowing how to write a program like this. Someday you might work on a project with me without knowing how to write a program like this. Then I would have to do you serious bodily harm. - Jack Klein

  3. #3
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    Nested classes don't scare me much. But on this case I'll stick to the friend declaration. Thanks
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

  4. #4
    Registered User manofsteel972's Avatar
    Join Date
    Mar 2004
    Posts
    317
    The way you have it now, you might just be able to generalize the GameMap class to handle any type of maptile by creating an abstract MapTile base class and derive MapHex class from that, but you wouldn't really need to unless you plan on reusing the code for square maptiles. As far as I know there really are only square and hex maptiles, so there probably isn't much need for it.
    "Knowledge is proud that she knows so much; Wisdom is humble that she knows no more."
    -- Cowper

    Operating Systems=Slackware Linux 9.1,Windows 98/Xp
    Compilers=gcc 3.2.3, Visual C++ 6.0, DevC++(Mingw)

    You may teach a person from now until doom's day, but that person will only know what he learns himself.

    Now I know what doesn't work.

    A problem is understood by solving it, not by pondering it.

    For a bit of humor check out xkcd web comic http://xkcd.com/235/

  5. #5
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    I don't see anything wrong with doing it this way. In a certain sense, a MapHex is like a trivial iterator on a GameMap.

    Of course, if this were STL the MapHex would probably be a nested class of GameMap. pianorain's suggesetion to do the reverse doesn't make much sense to me.

    But IMHO there's nothing wrong with doing it exactly how you've written it now.

  6. #6
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by manofsteel972 View Post
    The way you have it now, you might just be able to generalize the GameMap class to handle any type of maptile by creating an abstract MapTile base class and derive MapHex class from that, but you wouldn't really need to unless you plan on reusing the code for square maptiles. As far as I know there really are only square and hex maptiles, so there probably isn't much need for it.
    I think that would be overgeneralizing the code at this point.

  7. #7
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Design looks sound to me.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  8. #8
    Anti-Poster
    Join Date
    Feb 2002
    Posts
    1,401
    Quote Originally Posted by brewbuck View Post
    Of course, if this were STL the MapHex would probably be a nested class of GameMap. pianorain's suggesetion to do the reverse doesn't make much sense to me.
    Aye, it's a matter of access. If MapHex is a nested class of GameMap, GameMap does not have access to MapHex's private constructor. If GameMap is a nested class of MapHex, then GameMap does have access to MapHex's private constructor.

    Logically, I'd go GameMap::MapHex, but since GameMap needs access to a private constructor, to do it without friends I'd use MapHex::GameMap.
    If I did your homework for you, then you might pass your class without learning how to write a program like this. Then you might graduate and get your degree without learning how to write a program like this. You might become a professional programmer without knowing how to write a program like this. Someday you might work on a project with me without knowing how to write a program like this. Then I would have to do you serious bodily harm. - Jack Klein

  9. #9
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by pianorain View Post
    Logically, I'd go GameMap::MapHex, but since GameMap needs access to a private constructor, to do it without friends I'd use MapHex::GameMap.
    I think using a friend declaration is worth it.

  10. #10
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Definitely. Compromising your design in such a way just to avoid a friend declaration is ... not a good idea. That's what friends are for.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  11. #11
    (?<!re)tired Mario F.'s Avatar
    Join Date
    May 2006
    Location
    Ireland
    Posts
    8,446
    Thanks for the input folks.
    Originally Posted by brewbuck:
    Reimplementing a large system in another language to get a 25% performance boost is nonsense. It would be cheaper to just get a computer which is 25% faster.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Help with copy constructors
    By arya6000 in forum C++ Programming
    Replies: 2
    Last Post: 11-19-2008, 01:34 AM
  2. Copy constructors; Best practices (and private)
    By Mario F. in forum C++ Programming
    Replies: 15
    Last Post: 06-23-2006, 04:42 PM
  3. 'Passing by Refrence for Efficiency', Copy Constructors?
    By Zeusbwr in forum C++ Programming
    Replies: 4
    Last Post: 10-23-2004, 07:11 AM
  4. Copy constructors and operator=()
    By filler_bunny in forum C++ Programming
    Replies: 13
    Last Post: 08-25-2003, 07:43 AM
  5. Copy constructors and private constructors
    By Eibro in forum C++ Programming
    Replies: 5
    Last Post: 11-24-2002, 10:16 AM