Overloading the 'Index' Operator.. Twice

Started by
6 comments, last by SirLuthor 19 years, 6 months ago
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!
Free speech for the living, dead men tell no tales,Your laughing finger will never point again...Omerta!Sing for me now!
Advertisement
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?
HardDrop - hard link shell extension."Tread softly because you tread on my dreams" - Yeats
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.
Free speech for the living, dead men tell no tales,Your laughing finger will never point again...Omerta!Sing for me now!
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;}
Thanks! As is said, every little bit helps!
Free speech for the living, dead men tell no tales,Your laughing finger will never point again...Omerta!Sing for me now!
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:
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
Free speech for the living, dead men tell no tales,Your laughing finger will never point again...Omerta!Sing for me now!
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;}


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.
Free speech for the living, dead men tell no tales,Your laughing finger will never point again...Omerta!Sing for me now!

This topic is closed to new replies.

Advertisement