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?