Sign in to follow this  
password

operator overloading

Recommended Posts

I have a class named Block which instances are (going to be) stored in a two-dimensional std::vector. When I want to generate a new block, I set a another two-dimensional vector named "piece" to the value of this block instance stored in the vector.
// blocklib = (vector<vector<Block> > blocklib)
piece = blocklib[block][0]; // sets the player piece (ignore the 0 element for now)

class Block {
  public:
    Block(const int D[4][4]);
    
    std::vector<std::vector<int> > operator=(const int data[4][4]) const;
    
    int Data[4][4];
};

I made the return type a two-dimensional vector as well and I want to be able to set piece to an instance of this class, to make it simple.
std::vector<std::vector<int> > piece;

Block temp;
piece = temp;

The block.cpp file looks like this:
Block::Block(const int D[4][4]) {
    for (int x=0;x<4;x++) {
        for (int y=0;y<4;y++) {
            Data[x][y]=D[x][y];
        }
    }
}

std::vector<std::vector<int> > Block::operator=(const int data[4][4]) const {
    std::vector<std::vector<int> > temp;
    
    for (int x=0;x<4;x++) {
        for (int y=0;y<4;y++) {
            temp[x][y]=data[x][y];
        }
    }
    
    return temp;
}

I'm quite new to operator overloading and there are many parts of the code I haven't quite tested yet. You have any idea what can be wrong?

Share this post


Link to post
Share on other sites
No, that won't work I'm afraid. You are defining an = operator for Block, but then you are attempting to assign a Block to a vector<vector<int> >, which would require the operator = defined for the vector<vector<int> > type, not the block, which it obviously can't be.

I think what you want instead is a conversion operator:


class Block
{
operator vector<vector<int> >() const
{
vector<vector<int> > v;

//convert

return v;
}
};


although I'm not making any guarantees since I've never written a conversion operator that returns a vector of vectors. Think the principle is sound though.

Share this post


Link to post
Share on other sites
I'm not sure if it works correctly, but it compiled succesfully so it probably works. It's strange though, if I go off topic for a while and mention something about the project i'm working at. The files i've organized sometimes complain about "in file includes", but if I change something totally unrelevant to that problem, it just starts working by itself. This is making me feel kind of uneasy with everything, because the same thing can poop up again for no reason :)

I sort of know why this kind of error appears but it feels unavoidable because some files just most have the same includes. Shouldn't "#ifndef X_H_ - #define X_H_ - #endif" counter this problem?

For now it seems to be okay because there are no compiler errors, but I get the feeling these include errors appears when they want to, usually in relation with a compiler error. Is this just something that should be ignored?

Share this post


Link to post
Share on other sites
Quote:
Original post by password
I sort of know why this kind of error appears but it feels unavoidable because some files just most have the same includes. Shouldn't "#ifndef X_H_ - #define X_H_ - #endif" counter this problem?


That won't fix every kind of problem (especially if you have that exact same line in every header). It only prevents redeclaration errors caused by including the same file more than once.

Share this post


Link to post
Share on other sites
Quote:
Original post by password
For now it seems to be okay because there are no compiler errors, but I get the feeling these include errors appears when they want to, usually in relation with a compiler error. Is this just something that should be ignored?


I don't think any errors should ever just be ignored really.

What compiler and IDE are you using? Could you also explain the problem in a bit more detail, perhaps with some examples of the error messages you are getting and the relevant bits of the files it is complaining about? I don't really understand what you meant in your post.

Share this post


Link to post
Share on other sites
Quote:
Original post by EasilyConfused
Quote:
Original post by password
For now it seems to be okay because there are no compiler errors, but I get the feeling these include errors appears when they want to, usually in relation with a compiler error. Is this just something that should be ignored?


I don't think any errors should ever just be ignored really.

What compiler and IDE are you using? Could you also explain the problem in a bit more detail, perhaps with some examples of the error messages you are getting and the relevant bits of the files it is complaining about? I don't really understand what you meant in your post.


It's hard to explain but I can try. I'm using Dev-C++, I think the compiler is MinGW.

some of the error messages that appears

prototypes.h:6, from player.h In file included from prototypes.h:6, from player.h
player.h:6, from PBlocks.cpp from player.h:6, from PBlocks.cpp



block.h

#ifndef _BLOCK_H_
#define _BLOCK_H_

#include <vector>

// can't include prototypes.h here (see code block below why it
// doesn't work. The file "prototypes.h")

class Block {
....
};
#endif



prototypes.h

#ifndef _PROTOTYPES_H
#define _PROTOTYPES_H_

#include <SDL/SDL.h>

// it's probably because of this line "block.h".
// many of these includes feels necessary because I most
// have the Block class in the prototypes.h file
// and I most have the prototypes.h file in the block class

#include "block.h"

// prototypes.h - provides with the BlitSurface prototype for example.
// block.h - provides with the Block class so std::vector<Block> doesn't
// identify itself as an incorrect type.

const int SCREENWIDTH = 900;
const int SCREENHEIGHT = 600;

// board properties
const int BOARDWIDTH = 10;
const int BOARDHEIGHT = 17;

// --""--
const int BOARD_X_P1 = 191;
const int BOARD_Y_P1 = 99;
const int BOARD_X_P2 = 488;
const int BOARD_Y_P2 = 99;

const int BLOCKSIZE = 22;

extern std::vector<Block> blocklib;

extern SDL_Surface *blocks;
extern SDL_Rect blocktypes[4];

// prototypes

#endif



Maybe i'm doing something the wrong way, is there some rule when organizing files and in file include errors? I read the "organizing files in c++" tutorial here on gamedev yesterday and I couldn't find anything else than the #ifndef thing to prevent in file include errors.

Share this post


Link to post
Share on other sites
You have circular references in your include files. This is a Bad Thing. This usually comes about when you try to have some kind of "master include file," which is what "prototypes.h" appears to be. While this might seem like a cute organizational optimization, it actually makes your life more difficult and leads to longer compile times, so I suggest you stop using it.

Remember, include guards are only per-translation-unit. Circular reference issues can seem to magically appear and disappear at random because some times certain translation units don't need to be recompiled (their object file is up to date), and so the issue won't manifest itself again until they do. Issues like the compiler complaining about undefined symbol X even though you #include "X.h" right above can result from include guards yeilding a final translation unit where X's definition appears below declaration of a variable that uses the defintion, and so on (remember, #include is just textual subsitution into a translation unit).

In short, you need to remove prototypes.h and replace it with a proper, no-master-file-required header scheme.

If you can paste the full complement of errors and source code, I can probably tell you specifically what is wrong, but with what you've given so far I'd just be speculating, which won't help you much.

Share this post


Link to post
Share on other sites
I managed to make it work by making a new header file named "types.h" which I placed the following inside.


#include "block.h"

extern std::vector<Block> blocklib;




This way, I didn't need to include block.h in prototypes.h and I included types.h in player.h instead. Is this a good attempt to avoid "in file includes" or am I just solving this in a cheap way?

What I posted was about everything, but I can post how it looks like right now when it works.

types.h

#include "block.h"

extern std::vector<Block> blocklib;





prototypes.h

#ifndef _PROTOTYPES_H
#define _PROTOTYPES_H_

#include <SDL/SDL.h>

const int SCREENWIDTH = 900;
const int SCREENHEIGHT = 600;

// board properties
const int BOARDWIDTH = 10;
const int BOARDHEIGHT = 17;

// --""--
const int BOARD_X_P1 = 191;
const int BOARD_Y_P1 = 99;
const int BOARD_X_P2 = 488;
const int BOARD_Y_P2 = 99;

const int BLOCKSIZE = 22;

extern SDL_Surface *blocks;
extern SDL_Rect blocktypes[4];

// prototypes
void BlitSurface(int x, int y, SDL_Surface *image, SDL_Rect *area);
#endif





block.h

#ifndef _BLOCK_H_
#define _BLOCK_H_

#include <vector>

#include "prototypes.h"

class Block {
public:
Block(const int D[4][4]);

void draw() {
for (int x=0;x<4;x++) {
for (int y=0;y<4;y++) {
if (Data[x][y]!=0) BlitSurface(125+(x*22), 125+(y*22), blocks, &blocktypes[1]);
}
}
}

operator std::vector<std::vector<int> >() const {
std::vector<std::vector<int> > temp;

for (int x=0;x<4;x++) {
for (int y=0;y<4;y++) {
temp[x][y]=Data[x][y];
}
}

return temp;
}

int Data[4][4];
};
#endif





player.h

#ifndef _PLAYER_H_
#define _PLAYER_H_

#include <SDL/SDL.h>

#include "types.h"

class Player {
public:
Player(int startx) : x(startx), y(99), rotation(0), movetimer(0), nextblock(rand()%8), nexttype(rand()%3+1) { piece.resize(4*4); generateblock(); }

void input(); // input check
void draw(); // draw the block

void generateblock(); // generate a new block

// A player class representing one player where the start x position of a block varies

private:
int x,y; // x,y position

/* block variables */
int block; // current block type
int type; // current color
int nextblock;
int nexttype;

int movetimer;
int rotation;

std::vector<std::vector<int> > piece;
};

#endif




The main.cpp file doesn't help so much if I post, so I will leave that out for now. Instead of only having "prototypes.h" I made another header file named "types.h".

Share this post


Link to post
Share on other sites
Quote:

This way, I didn't need to include block.h in prototypes.h and I included types.h in player.h instead. Is this a good attempt to avoid "in file includes" or am I just solving this in a cheap way?

No, this is still just as bad, and it can still lead to the same problems. Why can't you just put the typedef for blocklib into block.h, with the rest of the block stuff?

Catch-all headers of almost any sort are bad. In addition to the #include nightmares that can result, they can seriously impact compile times because they introduce dependancies where dependancies don't exist.

types.h might seem benign now, but when type.h includes related typedefs for sixty or seventy classes, it will be a nightmare. A given translation unit might #include "types.h" for one type (say, blocklib), but if any of the seventy-odd types in types.h (or any of the files types.h includes) changes, that translation unit will be rebuilt unneccessarily. When sixty or seventy files rebuild because you changed one file unrelated to all of those, you'll regret using a catch-all header.

The proper solution is to put things like blocklib in block.h.
Any translation that needed to include types.h to get access to blocklib will need block.h included anyway, and this way you drastically reduce your potential for preprocessor screw-ups and dependancy issues.

Follow the principal of minimizing your dependancies.

Share this post


Link to post
Share on other sites
I think I understand things a little better now at least. One more and hopefully the last question. The two-dimensional vector piece I have in the Player class, can't be initialized like this:

vector<vector<int> > piece(4, vector<int>(4));

So I can't specifiy the amount of elements it should have.

When I remove the following line:
piece = blocklib[block]; // set the player piece

Which result in some kind of run-time memory error where the application just shuts down, it works again. This maybe is because I set the piece vector to another vector when the piece vector's size is actually 0 and doesn't have any elements.

piece.resize(16); doesn't work, probably because it's a two-dimensional vector.

Is it possible to allocate 4x4 slots into the piece vector in the constructor or at runtime somehow? With this I mean the same way it does when you make a vector like this.

vector<vector<int> > vec(COLS, vector<int>(ROWS));

Share this post


Link to post
Share on other sites
That's not a two-dimensional vector. It's a vector of vectors. Honestly, if your "2D array" is rectangular, you shouldn't use a vector of vectors. It's clunky. Instead, use a single vector and construct it like:

Block::Block(int width,int height)
: myVector(width * height);
{
// ...
}


Or something like that. Then you can remove the implicit conversion to vector-of-vectors and replace it with an overloaded operator() (or a getPart() method, or something) that looks like:


int Block::getPart(int x,int y) // int Block::operator()(int x,int y)
{
return (myVector[x + width * y]);
}


It will save you a lot of headaches in the long run.

Share this post


Link to post
Share on other sites
Quote:
Original post by jpetrie
That's not a two-dimensional vector. It's a vector of vectors. Honestly, if your "2D array" is rectangular, you shouldn't use a vector of vectors. It's clunky. Instead, use a single vector and construct it like:

Block::Block(int width,int height)
: myVector(width * height);
{
// ...
}

Or even better: welcome to the golden city of Boost.MultiArray.

Share this post


Link to post
Share on other sites
Last time I tested it only made things complicated. Well, I can give it another chance and use a single vector instead. Thanks for your help.

If i'm going to show the block on the screen, how would I do it the best way? If I were to do it, I would do it like this.


int ypos=0;
for (int i=0;i<(4*4);i++) {
if (Data[i]!=0) BlitSurface(125+(i*BLOCKSIZE), 125+ypos, blocks, &blocktypes[1]);
if ((i+1)%4==0) ypos+=BLOCKSIZE;
}



I'm sure you can do it with a formula but i'm not sure how.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this