Overloading the 'Index' Operator.. Twice
I was wondering this. As I'm working on a 2D linked list of sorts, I find myself wondering if you can overload, for example, this (given that the class name us 'Map'):
Map[x][y]->FUNCTION
I know it's possible to overload the first one, for this: Map[x]->FUNCTION, but I wish to know how, if possible, you can overload the double operator. Any pointers to set me on the right track would be greatly appreciated. Thanks!
You can't overload [][] directly but you have some alternatives you could overload operator() for (x,y) and get fairly close, the other option if you really really want [][] is to return some sort of proxy object that in turn have operator [] overloaded.
Did that make sense?
Did that make sense?
Yea, the (x,y) does seem to be the best (closest) route to take if I can't just set up the double-index directly :) Although, for some odd reason, I think the brackets look better.. Ahh, what is the world coming to, when programmers are worried about the cosmetics of their code... Anyway, thanks for the help, now I know.
just to elaborate that:
Quote:Original post by DigitalDelusion
you could overload operator() for (x,y) and get fairly close,
#include <cstddef>template < typename T >struct foo { typedef size_t size_type; const T& operator()(size_type x, size_type y) const; T& operator()(size_type x, size_type y);};
Quote:Original post by DigitalDelusion
the other option if you really really want [][] is to return some sort of proxy object that in turn have operator [] overloaded.
#include <cstddef>template < typename T >struct foo { typedef size_t size_type; T n[40]; const T& operator[](size_type x) const { return n[x]; } T& operator[](size_type x) { return n[x]; }};template < typename T >struct bar { typedef size_t size_type; foo<T> n[40]; const foo<T>& operator[](size_type y) const { return n[y]; } foo<T>& operator[](size_type y) { return n[y]; }};int main() { bar<int> b; b[0][0] = 30; b[0][1] = 55;}
Okay, instead of starting a new thread for what is essentially the same problem, I'll semi-raise this one. So, I worked out a method which seems to me to be good, and like it should work, however, I'm getting only one error now, and I'm really not understanding it, as it doesn't really give much in the way of background information... The error I'm getting is:
syntax error before '[' token.: Line 78
And the source code in question. The file main.cpp has been pruned down, and I added the line numbers in, so as to save space on the server :)
Any pointers as to why I'm getting that error would be appreciated. My thanks!
Main.cpp:
Map.hpp:
MapNodes.hpp:
TileCLASS.hpp:
syntax error before '[' token.: Line 78
And the source code in question. The file main.cpp has been pruned down, and I added the line numbers in, so as to save space on the server :)
Any pointers as to why I'm getting that error would be appreciated. My thanks!
Main.cpp:
23: #include "Map.hpp"27: #include "tileCLASS.hpp"35: Map gameMap;76: gameMap.Initialize(5, 6);78: gameMap.tile[3].[2]->removeGold();
Map.hpp:
#include "TileCLASS.hpp"#include "DEBUG.hpp"#include "MapNodes.hpp"using namespace std;enum AXIS { xAxis = 1, yAxis = 2 };class MapLink;//***********************************************************************************////*** Class Type: Map || Map class, acts as the bridge for the 2D linked list ***////***********************************************************************************//class Map{ public: Map(); Map(unsigned short x, unsigned short y = 1); ~Map(); unsigned short getXOffset() const; unsigned short getYOffset() const; void setXOffset(unsigned short x); void setYOffset(unsigned short y); void InsertRow(AXIS theAxis, int theCount = 1); void Initialize(unsigned short x = 1, unsigned short y = 1); void Insert(TILE * theData); void AllocateMem(); void Clear(); MapLink * tile; TILE * operator[](unsigned short tempYOffset); Node * Locate(unsigned short x, unsigned short y); private: Node * myHead; Node * myTail; Node * tempNode; unsigned short xOffset; unsigned short yOffset; unsigned short totalOffset; unsigned short offsetCounter; unsigned short xTileCount; unsigned short yTileCount; bool initialized; bool inserted;};//***********************************************************************************////*** Class Type: MapLink || MapLink class, adds some functionality to the ***////*** Map class, like the doubly overloaded index operator '[x]->[y]', and more ***////***********************************************************************************//class MapLink{ public: MapLink(Map * theMap); ~MapLink(); Map * operator[](unsigned short tempXOffset); private: Map * myMap;};//***********************************////*** Class Methods || MapLink ***////***********************************// MapLink::MapLink(Map * theMap): myMap(theMap){}MapLink::~MapLink(){} Map * MapLink::operator[](unsigned short tempXOffset){ myMap->setXOffset(tempXOffset); return myMap;}//*******************************////*** Class Methods || Map ***////*******************************//TILE * Map::operator[](unsigned short tempYOffset){ if (xOffset == 0 || yOffset == 0) { return NULL; } bool firstTime; firstTime = true; yOffset = tempYOffset; offsetCounter = (xOffset * yTileCount); offsetCounter = (offsetCounter - (yTileCount - yOffset)); if (firstTime = true) { tempNode = myHead->myNext; offsetCounter--; firstTime = false; } for ( ; offsetCounter > 0; offsetCounter--) { tempNode = tempNode->myNext; } return tempNode->myData;}unsigned short Map::getXOffset() const{ return xOffset;}unsigned short Map::getYOffset() const{ return yOffset;}void Map::setXOffset(unsigned short x){ xOffset = x;}void Map::setYOffset(unsigned short y){ yOffset = y;}Map::Map(): xOffset(0), yOffset(0), offsetCounter(0), totalOffset(0){ myHead = new HeadNode; initialized = false; inserted = false; tile = new MapLink(this);}Map::Map(unsigned short x, unsigned short y ): xTileCount(x), yTileCount(y), xOffset(0), yOffset(0), offsetCounter(0), totalOffset(0){ if (x == 0) { xTileCount = 1; #ifdef DEBUG printDEBUG("Error! Tried to create a map with 0 X tiles!\nxTileCount was set to 1\n"); #endif } if (y == 0) { yTileCount = 1; #ifdef DEBUG printDEBUG("Error! Tried to create a map with 0 Y tiles!\nyTileCount was set to 1\n"); #endif } initialized = true; inserted = false; tile = new MapLink(this);}Map::~Map(){ delete myHead;}void Map::Initialize(unsigned short x, unsigned short y){ if (initialized == false) { if (x == 0) { xTileCount = 1; #ifdef DEBUG printDEBUG("Error! Tried to create a map with 0 X tiles!\nxTileCount was set to 1\n"); #endif } else { xTileCount = x; } if (y == 0) { yTileCount = 1; #ifdef DEBUG printDEBUG("Error! Tried to create a map with 0 Y tiles!\nyTileCount was set to 1\n"); #endif } else { yTileCount = y; } initialized = true; inserted = false; AllocateMem(); } else { if (inserted == false) { AllocateMem(); } else { #ifdef DEBUG printDEBUG("Error! Tried to initialize a map that was already initialized!\n"); #endif } } }void Map::Insert(TILE * theData){ myHead->Insert(theData); #ifdef DEBUG printDEBUG("Node inserted into map through use of Map::Insert(TILE * theData)"); #endif} void Map::AllocateMem(){ // int tempX = 0; // int tempY = 0; int tiles = 0; int tempTiles = 0; bool conditions = false; TILE * theTile; tiles = xTileCount * yTileCount; if (initialized == true && inserted == false) { conditions == true; } if (conditions == true) { while (tempTiles < tiles) { theTile = new TILE; Insert(theTile); ++tempTiles; } inserted = true; } }
MapNodes.hpp:
// Remember to replace "TileClass.hpp" with the header that contains// the objects that you want to have stored in this linked list. Also,// remember to change 'TILE' to the class name of your choice.//// This file should not be changed around except for those things mentioned// above.#ifndef MAPNODES_HPP#define MAPNODES_HPP#include "TileClass.hpp"#include "DEBUG.hpp"#define TILE tileObjectusing namespace std; class Map;//***********************************************************************////*** Abstract Data Type: Node || Base class for other node types ***////***********************************************************************//class Node{ public: Node(); virtual ~Node(); virtual void Insert(TILE * theData) = 0; virtual void setNext(Node* theNext) = 0; friend class Map; private: Node * myNext; TILE * myData;};Node::Node(){}Node::~Node(){}//*************************************************////*** Internal Node || InternalNode Methods ***////*************************************************//class InternalNode: public Node{ public: InternalNode(TILE * theData, Node * next, Node * last); virtual ~InternalNode(); virtual void Insert(TILE * theData); virtual void setNext(Node * theNext); private: TILE * myData; Node * myNext; Node * myLast;};InternalNode::InternalNode(TILE * theData, Node * next, Node * last): myData(theData), myNext(next), myLast(last){ #ifdef DEBUG printDEBUG("InternalNode Constructer!\n"); #endif}InternalNode::~InternalNode(){ delete myData; delete myNext; #ifdef DEBUG printDEBUG("InternalNode Destructer!\n"); #endif}void InternalNode::Insert(TILE * theData){ myNext->Insert(theData);}void InternalNode::setNext(Node * theNext){ myNext = theNext;}//*****************************************////*** Tail Node || TailNode Methods ***////*****************************************//class TailNode : public Node{ public: TailNode(Node * last); virtual ~TailNode(); virtual void Insert(TILE * theData); virtual void setNext(Node * theNext); private: Node * myLast; Node * myLastTemp;};TailNode::TailNode(Node * last): myLast(last), myLastTemp(last){ #ifdef DEBUG printDEBUG("TailNode Constructer!\n"); #endif} TailNode::~TailNode(){ #ifdef DEBUG printDEBUG("TailNode Destructer!\n"); #endif} void TailNode::Insert(TILE * theData){ myLast = new InternalNode(theData, this, myLast); myLastTemp->setNext(myLast); myLastTemp = myLast;}void TailNode::setNext(Node * theNext){} //*****************************************////*** Head Node || HeadNode Methods ***////*****************************************//class HeadNode : public Node{ public: HeadNode(); virtual ~HeadNode(); virtual void Insert(TILE * theData); virtual void setNext(Node * theNext); private: Node * myNext;};HeadNode::HeadNode(){ myNext = new TailNode(this); #ifdef DEBUG printDEBUG("HeadNode Constructer!\n"); #endif}HeadNode::~HeadNode(){ delete myNext; #ifdef DEBUG printDEBUG("HeadNode Destructer!\n"); #endif} void HeadNode::Insert(TILE * theData){ myNext->Insert(theData);}void HeadNode::setNext(Node * theNext){ myNext = theNext;}//*** Other stuff ***//#endif
TileCLASS.hpp:
#ifndef TileCLASS_HPP#define TileCLASS_HPPclass tileObject{ public: tileObject(); ~tileObject(); int getXPos() const; int getYPos() const; int getTileID() const; void setXPos(int tempX); void setYPos(int tempY); void setTileID(int tempID); int getDirOpen(int tempDir); int getGold() const; void removeGold(); private: int xPos; int yPos; int tileID; bool dirOpenUp; bool dirOpenRight; bool dirOpenDown; bool dirOpenLeft; bool gold;};#endif
I had a quick glance so it might no be it, in your overloaded subscript operators return a reference to the type in question, like in the example i showed earlier, all you need to do is just deference the pointer before returning e.g.
also you mentioned something about a 2d linked list earlier? might wont to looking into using the standard library list instead and make a list of list of tiles e.g.
and if you only wont a singely-linked list then there is an STL extension called slist but currently not in c++ standard as of yet but most compilers support it e.g.
EDIT: clickies: list, slist, and STL in general
const Map& MapLink::operator[](unsigned short tempXOffset) const { myMap->setXOffset(tempXOffset); return *myMap;}Map& MapLink::operator[](unsigned short tempXOffset) { myMap->setXOffset(tempXOffset); return *myMap;}
also you mentioned something about a 2d linked list earlier? might wont to looking into using the standard library list instead and make a list of list of tiles e.g.
#include <list>std::list< std::list<TILE> > my_2d_list_of_tiles;
and if you only wont a singely-linked list then there is an STL extension called slist but currently not in c++ standard as of yet but most compilers support it e.g.
#include <slist>std::slist< std::slist<TILE> > my_2d_list_of_tiles;
EDIT: clickies: list, slist, and STL in general
Quote:
I had a quick glance so it might no be it, in your overloaded subscript operators return a reference to the type in question, like in the example i showed earlier, all you need to do is just deference the pointer before returning e.g.
const Map& MapLink::operator[](unsigned short tempXOffset) const {
myMap->setXOffset(tempXOffset);
return *myMap;
}
Map& MapLink::operator[](unsigned short tempXOffset) {
myMap->setXOffset(tempXOffset);
return *myMap;
}
So basically, your saying that that operator should return a reference as opposed to the pointer it's returning now? I would do that, however, I can not see how I can do that, as the only link to the MapLink in Map, and the Map in MapLink is a pointer. Is there a way to, well, make a reference from a pointer? Or, is there a way to have references as class members? Because I read that references have to be initialized on creation, and, well, I don't know if that would work to well in a class.
[EDIT] I think you can disregard the above bit, I just (think) I saw what you are getting at. Will try it out now. Thanks!
Also, regarding the 2D Linked List, well, I figured it would be better practice, and help me learn something difficult for me, if I did it myself :) It's been a most valuable learning experience, I'll tell you that.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement