Can I initialize an array within a class header file.

Hi,

I have been making a simple tetris game and so far it's just a linear main.cpp file. I understand that I should be trying to encapsulate the program, so I'm in the process of working out how this can be done.

I wish to create a class to contain the tetris block shapes, which are stored in a series of 2d arrays.

e.g. for the L shape
1
2
3
4
5
{0,0,0,0,0},
{0,0,1,0,0},
{0,0,1,0,0},
{0,0,1,1,0},
{0,0,0,0,0}


The problem that I have is that I cannot seem to initialize the array in the class. At first I tried to assign values for the array in a constructor, however I learned that I cannot use the {} outside of initialization. So I tried to initialize an array within the class header file. This seems to be problematic also

In my test project I have two files testarray.h and main.cpp

testarray.h
1
2
3
4
5
6
7
8
9
10
11
#ifndef TESTARRAY_H_ 
#define TESTARRAY_H_

class TestArray
{
public:
	
     int m_Array [2] = {0,1}; 

};
#endif 


main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include "testarray.h"


int main()
     {	
	TestArray test1;

	std::cout<< test1.m_Array[0] << test1.m_Array[1];

	std::cin.get(); // wait
		
	return 0;
     }


When I compile this I get a lot of errors all regarding the array.

I'm sure that I doing something very wrong but cant work it out. Is there any way I can initialize an array with {} within a class?
You can in C++ 11 AFAIR. Why won't you just define default constructor?
EDIT: Yes, you can. Works for me.
Last edited on
EDIT:

I must be doing something wrong then.

I now have 3 files testarray.h , testarray.cpp and main.cpp

testarray.h
1
2
3
4
5
6
7
8
9
10
11
#ifndef TESTARRAY_H_ 
#define TESTARRAY_H_

class TestArray
{
public:
	
	TestArray ();
	int m_Array [2];
};
#endif 


testarray.cpp
1
2
3
4
5
6
#include "testarray.h"

TestArray::TestArray()
{
	m_Array [2] = {0,1};
}


main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include "testarray.h"


int main()
	{
		
		TestArray test1;

		std::cout<< test1.m_Array[0] << test1.m_Array[1];

		std::cin.get(); // wait
		
		return 0;
		}



OLD POST

I tried a default constructor:

1
2
3
4
5
6
7
8
9
10
11
12
#ifndef TESTARRAY_H_ 
#define TESTARRAY_H_

class TestArray
{
public:

     TestArray();	
     int m_Array [2];

};
#endif 


1
2
3
4
TestArray()
{
     m_Array [2] = {0,1};
}


However I don't think the {} are valid in the constructor.

I realise that in this example it would be a simple matter to set up a for loop and fill the array. However, the tetris blocks would not be so simple, if I cant use the {}.
Last edited on
a) You do not need to create own blocks to each class object, right? You might want to use static variables:
1
2
3
4
5
6
7
8
9
10
11
//.h
class Tetris
{
    static const int shape_L[4][4];
};
//.cpp

const int Tetris::shape_L[4][4] = {{0, 0, 0, 0},
                                   {0, 0, 1, 0},
                                   {0, 0, 1, 0},
                                   {0, 1, 1, 0}};
Or you can update your compiler. Because code you posted first should be valid in C++11.
Last edited on
Thanks :-)

I can see now what I did wrong

original:
1
2
3
4
5
6
#include "testarray.h"

TestArray::TestArray()
{
     m_Array [2] = {0,1};
}


working:
1
2
3
4
5
6
#include "testarray.h"

TestArray::TestArray()
{
	int m_Array [2] = {0,1};
}


I didnt include the int, didnt think I could do this as I declared the array in the class header.

thanks again
Last edited on
^ That won't work.
This will create a NEW array variable.
Your "Real" m_Array won't get edited.
It's like you are creating that variable in a different scope.

It's weird your compiler didn't warn you.
What compiler are you using?
Gutted, your right (should have ran the program first)

It compiled fine, I'm using Visual C++ Studio Express 2010.

I'm trying to make a class to store that shape data array, I dont want it set in the main.cpp otherwise I might as well just do away with the class.

EDIT

Ok would this be an acceptable work around before I get C++ 11.

testarray.cpp
1
2
3
4
5
6
7
8
9
10
11
#include "testarray.h"

int t_Array [2] = {0,1};

TestArray::TestArray()
{
	for (int i=0; i < 2; ++i)
	{
	m_Array [i] = t_Array [i];
	}
}


so in this, Ive made a template array (t_array) and then in the constructor I set up a loop which fills m_Array with the template.

Is this an acceptable work around or is it very bad practice? I'm learning from a book and I imagine that my code is not very elegant.
Last edited on
It's not the best of things you could do (You could basically do the same using the "Static" example you can see above)
What about using parameters for initializing it?

Like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Declaration:
class TestArray {
    int m_Array[8];
    TestArray(int * Array = 0);
};

// Definition:
TestArray::TestArray(int * Array)
{
    if(!Array)
        return;
    for(int i = 0; i < 8; ++i)
    {
        m_Array[i] = Array[i];
    }
}

// Usage:

int yourarray[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
TestArray array(yourarray);
TestArray other; // Also works, but you may want to specify a different default constructor 
Last edited on
Sorry please excuse my ignorance, I'm just starting out.

However in your usage would this code be contained in the main.cpp file?

The reason that I want to use a class is to store the contents of the array in a separate file. As I thought this would be good practice in terms of encapsulation.
Yes, the Usage is an example code on how it looks like, but it's not required to be in the main.cpp file.
It can also be in an imaginary Ghost.cpp file.

If you want to store the contents of the array in a separate file, you should do something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Polygons.h

// Virtual class named BasePolygon. Solid base for derivate classes.
class BasePolygon {
    virtual ~BasePolygon();
    inline int * GetShape() { return m_Array; }
    inline void Set(int * ptr) { for(int i = 0; i < 25; ++i) { m_Array[i] = ptr[i]; } }
    int m_Array[25]; // <- your polygon is stored here
};

class Polygon_T_Shape : public BasePolygon {
    Polygon_T_Shape();
};

// Polygons.cpp
BasePolygon::~BasePolygon() {}

Polygon_T_Shape::Polygon_T_Shape() {
    int YourShape[25] = {
        0, 0, 1, 0, 0,
        0, 0, 1, 0, 0,
        0, 0, 1, 0, 0,
        0, 0, 1, 1, 0,
        0, 0, 0, 0, 0
    };
    Set(YourShape);
}


Now, at this point, you can have:

1
2
3
4
5
6
std::vector<BasePolygon *> Polygons;
Polygons.push_back(new Polygon_T_Shape);

int * shape = Polygons[0].GetShape(); // First polygon shape!

// BUT! Remember to delete all pointers inside Polygons once you're done with it! 


And, to add a new shape:

1
2
3
4
5
6
7
8
9
10
11
12
// End of polygons.h:
class MyNewPolygonName : public BasePolygon {
    MyNewPolygonName();
};

// End of polygons.cpp:
MyNewPolygonName::MyNewPolygonName() {
    int YourShape[25] = {
        // Your polygon
    };
    Set(YourShape);
}


And poof, you're done.

Limitations:
1. Your polygon can only be of 25-size (You can edit this by changing all "25" to your custom size)
2. You must free your items after usage, if you want to store them on a std::vector

Positives:
1. You can use a std::vector and change your code a bit to make it arbitrary-sized
2. You can make your own std::vector or you can use an std::auto_ptr to solve Limitation #2
3. Using std::vector<BasePolygon *>, you can "Enumerate" its contents to easily have all shapes in a single place

Failing to delete your Polygons' content before it goes out of scope will result in (4 * 25 = 100) bytes of leak for each polygon contained.

ADVERTISEMENT:
My custom classes (Who, FYI, are being updated a lot these days for the public @ SF.net but aren't published yet) could allow me a safer and faster std::vector/std::auto_ptr coupling.
But they aren't published yet :'D

EDIT: Typos: Polygon_T_Shape should be Polygon_L_Shape
Last edited on
Thankyou for the indepth reply! I'll have to google quite a lot of it, as I'm not confident on the use of pointers and although have heard of memory leak and vectors I have no experience with either. Thanks again.
So, it's better if I suggest you another way, trust me.

There we go, again, arrays:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Polygons.h
enum PolygonType {
    PT_L_SHAPE = 0, // First polygon will be L-shaped
    PT_T_SHAPE, // Second polygon will be T-shaped
    PT_COUNT
};
int * GetPolygon(PolygonType Type);

// Polygons.cpp
int AllPolygons[PT_COUNT][25] = {
    { 0, 0, 1, 0, 0, // First polygon, L-shaped
       0, 0, 1, 0, 0,
       0, 0, 1, 0, 0,
       0, 0, 1, 1, 0,
       0, 0, 0, 0, 0 },
    { 0, 0, 0, 0, 0, // Second polygon, T-shaped
       0, 1, 1, 1, 0,
       0, 0, 1, 0, 0,
       0, 0, 1, 0, 0,
       0, 0, 0, 0, 0 }
};
int* GetPolygon(PolygonType Type)
{
    if(Type >= PT_COUNT) // Invalid polygon chosen?
        return 0;
    return AllPolygons[Type];
}


The way you can use it will look like:
1
2
3
4
5
int * MyPolygon = GetPolygon(PT_L_SHAPE); // Get a L-shaped polygon!
if(!MyPolygon)
{
    // Error occurred (Should not happen)
}


To add more polygons:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Polygons.h
enum PolygonType {
    PT_L_SHAPE = 0, // First polygon will be L-shaped
    PT_T_SHAPE, // Second polygon will be T-shaped
    // Add your new polygon type name here, like, PT_PLUS_SHAPE
    // Another example, PT_CROSS_SHAPE
    PT_COUNT
};

int AllPolygons[PT_COUNT][25] = {
    /* Old polygons */,
    {
        // Your new polygon here. This one will be PT_PLUS_SHAPE, because it's after PT_T_SHAPE, who is after PT_L_SHAPE who is the first.
    },
    {
       // Another polygon here, PT_CROSS_SHAPE
    }
};


Which is relatively simple.
It requires no memory freeing or vectors.
Last edited on
Topic archived. No new replies allowed.