Skip to main content
gamedev.net
🔒 Locked

Overloading []

Started by caseyd Mar 24, 2006 at 8:54 PM 10 replies 1.2k views
Original Post
caseyd
caseyd
I can't seem to get the overloading of the [] operator for this Array Template to work. I keep getting this error: error C2676: binary '[' : 'Array' does not define this operator or a conversion to a type acceptable to the predefined operator with [ DataType=int ] Here's my code:


#include <iostream>

using namespace std;

// Array Template

template <class DataType>
class Array {

public:
	DataType * m_array;
	int m_size;

	// Constructor. Takes the size of the array to create
	// as an argument.
	Array( int p_size )
	{
		// Create an array of DataType with given size.
		m_array = new DataType[p_size];
		m_size = p_size;
	}

	// Destructor - Checks to see if the array has
	// been initialized and if so, destroys it.
	~Array()
	{
		if ( m_array != 0 ) {
			delete[] m_array;
		}
	}

	// resize - Resizes the current array to
	// p_size.
	void resize( int p_size ) 
	{
		// Create a temporary array
		DataType * tempArray = new DataType[p_size];

		// Check to make sure that the temp array
		// was initialized okay.
		if ( newArray != 0 ) {
			
			// Determine if the new size of the array 
			// is larger or smaller than the old size.
			// If it is smaller, all data in the old array
			// past that point will be lost. If it is larger
			// we can only copy over the data that was
			// in the original array.
			int min = p_size < m_size ? p_size : m_size;

			int index;

			// Copy the contents of the old array into
			// the temp array.
			for ( index = 0; index < min; index++ ) {
				newArray[index] = m_array[index];
			}

			// Update the size of the new array.
			m_size = p_size;

			// Delete the old array.
			if ( m_array != 0 ) {
				delete[] m_array;
			}

			// Set the old array to the new array 
			// and we are done.
			m_array = newArray;

		}

		// Overload the [] operator so we can use
		// this array just like any other array.
		DataType& operator[](int p_index) 
		{
			return m_array[p_index];
		}

		// Overload the conversion operator so 
		// we can seamlessly pass this into a 
		// function.
		operator Array::DataType* ()
		{
			// Simply return a pointer to the array.
			return m_array;
		}
	}

};

int main()
{
	
	Array<int> intArray(10);

	intArray[5] = 6;

	cout << intArray[5] << endl;

	return 0;
}

I am using Visual C++ 2005 Express as well. I've tried fooling around with it a couple of different ways but I just seem to be making it worse. Thanks for the help.
Sneftel
Sneftel
You're declaring your operators as local functions within resize(). (Is that even allowed?)
caseyd
caseyd
I don't know.. I've seen an example do it the same way. I also tried doing it the way it's done in the C++ complete reference, which gives me this:

// Method declaration inside classDataType& operator[](int p_index);// Method body outside classDataType& Array::operator[](int p_index) {	return m_index[p_index];}



But this gives me even more errors:
c:\projects\cpp\lab\lab\main.cpp(94) : error C2143: syntax error : missing ';' before '&'
c:\projects\cpp\lab\lab\main.cpp(94) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
c:\projects\cpp\lab\lab\main.cpp(94) : error C2955: 'Array' : use of class template requires template argument list
c:\projects\cpp\lab\lab\main.cpp(92) : see declaration of 'Array'
c:\projects\cpp\lab\lab\main.cpp(94) : error C2039: '[]' : is not a member of 'Array'
c:\projects\cpp\lab\lab\main.cpp(92) : see declaration of 'Array'
c:\projects\cpp\lab\lab\main.cpp(94) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
c:\projects\cpp\lab\lab\main.cpp(95) : error C2065: 'm_index' : undeclared identifier
c:\projects\cpp\lab\lab\main.cpp(95) : warning C4508: '[]' : function should return a value; 'void' return type assumed


Do I maybe have to do something different since I'm using a templated class?
Programmer16
Programmer16
As sneftel said your code doesn't work because you're declaring your operators within a function. You need to move the function's (resize()) closing brace:
#include <vector>#include <string>#include <iostream>#include "FackinAround.h"#include <iostream>using namespace std;// Array Templatetemplate <class DataType>class Array {public:	DataType * m_array;	int m_size;	// Constructor. Takes the size of the array to create	// as an argument.	Array( int p_size )	{		// Create an array of DataType with given size.		m_array = new DataType[p_size];		m_size = p_size;	}	// Destructor - Checks to see if the array has	// been initialized and if so, destroys it.	~Array()	{		if ( m_array != 0 ) {			delete[] m_array;		}	}	// resize - Resizes the current array to	// p_size.	void resize( int p_size ) 	{		// Create a temporary array		DataType * tempArray = new DataType[p_size];		// Check to make sure that the temp array		// was initialized okay.		if ( newArray != 0 ) {						// Determine if the new size of the array 			// is larger or smaller than the old size.			// If it is smaller, all data in the old array			// past that point will be lost. If it is larger			// we can only copy over the data that was			// in the original array.			int min = p_size < m_size ? p_size : m_size;			int index;			// Copy the contents of the old array into			// the temp array.			for ( index = 0; index < min; index++ ) {				newArray[index] = m_array[index];			}			// Update the size of the new array.			m_size = p_size;			// Delete the old array.			if ( m_array != 0 ) {				delete[] m_array;			}			// Set the old array to the new array 			// and we are done.			m_array = newArray;		}        }// now its here.		// Overload the [] operator so we can use		// this array just like any other array.		DataType& operator[](int p_index) 		{			return m_array[p_index];		}		// Overload the conversion operator so 		// we can seamlessly pass this into a 		// function.		// I also had to remove Array:: from below:		operator DataType*()		{			// Simply return a pointer to the array.			return m_array;		}	//} was here};int main(){		Array<int> intArray(10);	intArray[5] = 6;	cout << intArray[5] << endl;	return 0;}

This compiles and works correctly (I'm using MSVS .NET 2K3)
caseyd
caseyd
Smacks head than proceeds to beat head against desk...

That was easily one of the most stupid errors I've made in a while.. I didn't even completely realize what Sneftel was telling me...

Thanks for making me realize this. I probably would have been messing with it for a while..
caseyd
caseyd
Well, I got everything working. Now I am still learning Templates and what not, but is there anyting I can do to make this class better or more useful?
joanusdmentia
joanusdmentia
Use the explicit keyword to prevent the compiler from using conversions implicitly (unless that's what you want, of course). For example, with you're code atm you could do the following:
int main(){		Array<int> intArray(10);	intArray = 6;	cout << intArray.size() << endl;	return 0;}

This would create a new array with 6 elements and you'll loose all of it's previous contents (probably resulting from a typo where you forgot the index).

This is how you'd use the explicit keyword:
template<class DataType>class Array {public:    //...    explicit Array( int p_size ) { ... }    //...    explicit operator Array::DataType* () { ... }};


Why are m_array and and m_size public? These members should be private.

There's no need to check that m_array!=0 before delete'ing it, deleting a NULL pointer is perfectly safe and does nothing.

Provide const versions of the operator[] and operator Array::DataType* functions.

....and I'll be good and not mention anything about exception safetly and using std::vector [smile]
"Voilà! In view, a humble vaudevillian veteran, cast vicariously as both victim and villain by the vicissitudes of Fate. This visage, no mere veneer of vanity, is a vestige of the vox populi, now vacant, vanished. However, this valorous visitation of a bygone vexation stands vivified, and has vowed to vanquish these venal and virulent vermin vanguarding vice and vouchsafing the violently vicious and voracious violation of volition. The nly verdict is vengeance; a vendett o
caseyd
caseyd
Quote:
Provide const versions of the operator[] and operator Array::DataType* functions.


Could you explain the reasoning behind having these methods const? Is it because they don't change anything within the class? Should there only be const methods of these?

Quote:
....and I'll be good and not mention anything about exception safetly and using std::vector


This is the kind of advice I'm really interested in..I'm going to start another post around this subject since this is starting to go a little off the original topic, and I think more people would benefit from this.
CrazyCdn
CrazyCdn
Here's a link to why it should be const:
http://www.parashift.com/c++-faq-lite/const-correctness.html

It really makes catching mistakes/errors a lot easier when you use it correctly I've found. At first I disliked it, I still make a class, get it working then go back and make it const correct (most times within minutes, shouldn't take long to get a class up and running).
"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin
joanusdmentia
joanusdmentia
Quote:
Original post by caseyd
Quote:
Provide const versions of the operator[] and operator Array::DataType* functions.


Could you explain the reasoning behind having these methods const? Is it because they don't change anything within the class? Should there only be const methods of these?


Let's say for example you're passing an Array through to your Renderer class. You don't want your Renderer class to be changing the contents of the array so have a render function like the following to ensure this:
class Renderer{    //...    void render(const Array<IRenderable>& vertices);};

Now inside your render() function you need to access the individual vertices with operator[], BUT if you don't have a const version of operator[] you won't be able to. Hence, you provide both const and non-const version of operator[].

Quote:
Original post by caseyd
Quote:
....and I'll be good and not mention anything about exception safetly and using std::vector


This is the kind of advice I'm really interested in..I'm going to start another post around this subject since this is starting to go a little off the original topic, and I think more people would benefit from this.
[/quote]

Fair enough, but be warned that if you *really* want to get into the nitty gritty it can get fairly complicated.
"Voilà! In view, a humble vaudevillian veteran, cast vicariously as both victim and villain by the vicissitudes of Fate. This visage, no mere veneer of vanity, is a vestige of the vox populi, now vacant, vanished. However, this valorous visitation of a bygone vexation stands vivified, and has vowed to vanquish these venal and virulent vermin vanguarding vice and vouchsafing the violently vicious and voracious violation of volition. The nly verdict is vengeance; a vendett o
caseyd
caseyd
Thanks. I read through the C++ faq on const correctness, I need to read it again though and try out a few things to really get it down. I am already seeing how complicated even something like this can get. It's really great though as going through this stuff is really showing me where I need to improve.

Thanks for all of your replies.
bakery2k1
bakery2k1
...        // resize - Resizes the current array to	// p_size.	void resize( int p_size ) 	{		// Create a temporary array		DataType * tempArray = new DataType[p_size];		// Check to make sure that the temp array		// was initialized okay.		if ( newArray != 0 ) {


Is "newArray" here supposed to be "tempArray"? If so, there is no need to check whether it is 0 - new will either return a pointer to a valid memory allocation or will throw a std::bad_alloc exception.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.