Archived

This topic is now archived and is closed to further replies.

null_pointer

Array template class woes...

Recommended Posts

I created a generic array class using c++ templates, but it can't use the array subscript operators, unless I do messy casts. Here's an example of what I have to do to make it work: Array arString(10); // like char[10] arString[1] = 6; // won't compile ((char*) arString)[1] = (char) 6; // compiles and works I have a whole slew of operators defined, so it should do an implicit conversion to the type's pointer type (in this case, int*), which should work with the subscripts. In fact, the =, +, and += operators can use the subscripts fine without all the casting. Freeyellow.com doesn't accept .zip files (argh!) so I have to post the whole file here: in Array.hpp #if !defined(AFX_ARRAY_HPP__24138A00_04E1_11D4_AB54_0050BAB009EE__INCLUDED_) #define AFX_ARRAY_HPP__24138A00_04E1_11D4_AB54_0050BAB009EE__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 namespace GDL { ///////////////////////////////////////////////////////////////////////// // // namespace GDL::Array // ///////////////////////////////////////////////////////////////////////// template class Array { public: // Class-specific data types public: // Constructors/Destructor explicit Array(const unsigned long nSize); virtual ~Array(); private: Array(); // disabled public: // Interface functions virtual void Resize(const unsigned long nSize); virtual Array& operator =(const Array& arArray); virtual Array operator +(const Array& arArray) const; inline Array& operator+=(const Array& arArray); // inline Type& operator[](const unsigned long nIndex); // inline const Type& operator[](const unsigned long nIndex) const; inline operator Type*(); inline operator const Type*() const; public: // Accessor functions inline const Type* GetElements() const; inline const unsigned long GetSize() const; protected: // Worker functions protected: // Data members Type* m_pElements; unsigned long m_nSize; }; ///////////////////////////////////////////////////////////////////////// // Accessor functions ///////////////////////////////////////////////////////////////////////// template inline Array& Array::operator+=(const Array& arArray) { return( (*this) = ((*this) + arArray) ); } /* template inline Type& Array::operator[](const unsigned long nIndex) { return( m_pElements[nIndex] ); } template inline const Type& Array::operator[](const unsigned long nIndex) const { return( m_pElements[nIndex] ); }*/ template inline Array::operator Type*() { return( m_pElements ); } template inline Array::operator const Type*() const { return( m_pElements ); } template inline const Type* Array::GetElements() const { return( m_pElements ); } template inline const unsigned long Array::GetSize() const { return( m_nSize ); } ///////////////////////////////////////////////////////////////////////// // // namespace GDL::Array // ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// // Constructors/Destructor ///////////////////////////////////////////////////////////////////////// template Array::Array(const unsigned long nSize) : m_pElements(new Type[nSize]), m_nSize(0) { } template Array::~Array() { // Destroy the array SafeDeleteArray(m_pElements); } template Array::Array() : m_pElements(0), m_nSize(0) { } ///////////////////////////////////////////////////////////////////////// // Interface functions ///////////////////////////////////////////////////////////////////////// template void Array::Resize(const unsigned long nSize) { // Create a new array Type* pNewElements = new Type[nSize]; // Copy the old array into the new array const unsigned long nElementsToCopy = Minimum(m_nSize, nSize); for( unsigned long x=0; x < nElementsToCopy; x++ ) { pNewElements[x] = m_pElements[x]; } // Destroy the array SafeDeleteArray(m_pElements); // Store the new array m_pElements = pNewElements; m_nSize = nSize; } template Array& Array::operator =(const Array& arArray) { // Create a new array Type* m_pElements = new Type[arArray.GetSize()]; m_nSize = arArray.GetSize(); // Copy the other array into our new array for( unsigned long x=0; x > m_nSize; x++ ) { m_pElements[x] = arArray[x]; } return( *this ); } template Array Array::operator +(const Array& arArray) const { // Create a new, empty array Array arNewArray; // Get the total number of elements in the new array const unsigned long nElements = (m_nSize + arArray.m_nSize); arNewArray.m_pElements = new Type[nElements]; for( unsigned long x=0; x < m_nSize; x++ ) arNewArray[x] = m_pElements[x]; for( unsigned long y=0; y < arArray.m_nSize; y++ ) arNewArray[(x + y)] = arArray[y]; return( arNewArray ); } ///////////////////////////////////////////////////////////////////////// // Worker functions ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// // Data members ///////////////////////////////////////////////////////////////////////// }; #endif // !defined(AFX_ARRAY_HPP__24138A00_04E1_11D4_AB54_0050BAB009EE__INCLUDED_) And here is the error:
quote:
Original post by my compiler C:\PROGRAM FILES\MICROSOFT VISUAL STUDIO\MYPROJECTS\Game Development Library\String.cpp(67) : error C2679: binary '=' : no operator defined which takes a right-hand operand of type 'char' (or there is no acceptable conversion)
My String class just uses an Array. Where is the problem? I'm just about cross-eyed from reading code today... Thanks for your time!
- null_pointer Sabre Multimedia Edited by - null_pointer on 4/3/00 8:08:59 PM Edited by - null_pointer on 4/3/00 8:10:36 PM

Share this post


Link to post
Share on other sites
Someone correct me if I''m wrong, but I think you are defining your template class incorrectly (at least, I''ve never seen it done that way before )

You are missing the

template <typename Type>

oh, wait... now that I think about it you probably have that and it was taken out my the message board

Well, in that case... could you add them back in or post the code file somewhere so I can take a look? You can email it to me too if you want and I''ll be happy to take a look and see if I can figure out what''s going on...

Sorry I can''t be of more help now, though

Check out the GPI project today!

Share this post


Link to post
Share on other sites
Well, I hope this solution doesn''t break your style

First I had to replace your Minimum function with stdlib''s min. Next I replaced all the calls to SafeDelete with delete []''s. Instead of working with the casting operators, I chose to use the array subscript operator. Because of this, I had to add a operator + function to the mix, but that was trivial.
Here''s the code that compiles under BCB 4 Pro.


#if !defined(AFX_ARRAY_HPP__24138A00_04E1_11D4_AB54_0050BAB009EE__INCLUDED_)
#define AFX_ARRAY_HPP__24138A00_04E1_11D4_AB54_0050BAB009EE__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "stdlib.h"

namespace GDL {


/////////////////////////////////////////////////////////////////////////
//
// namespace GDL::Array < Type >
//
/////////////////////////////////////////////////////////////////////////


template < class Type >
class Array
{
public:
// Class-specific data types

public:
// Constructors/Destructor
explicit Array(const unsigned long nSize);
virtual ~Array();

private:
Array(); // disabled

public:
// Interface functions
virtual void Resize(const unsigned long nSize);

virtual Array < Type > & operator =(const Array < Type > & arArray);
virtual Array < Type > operator +(const Array < Type > & arArray) const;
inline Array < Type > & operator+=(const Array < Type > & arArray);

inline Type& operator[](const unsigned long nIndex);
inline Type* operator+(unsigned long nIndex) const;
// inline const Type& operator[](const unsigned long nIndex) const;

//inline operator Type*();
//inline operator const Type*() const;

public:
// Accessor functions
inline const Type* GetElements() const;
inline const unsigned long GetSize() const;

protected:
// Worker functions

protected:
// Data members
Type* m_pElements;

unsigned long m_nSize;

};


/////////////////////////////////////////////////////////////////////////
// Accessor functions
/////////////////////////////////////////////////////////////////////////


template < class Type >
inline Array < Type > & Array < Type > ::operator+=(const Array < Type > & arArray)
{ return( (*this) = ((*this) + arArray) ); }


template < class Type >
inline Type& Array < Type > ::operator[](const unsigned long nIndex)
{ return( m_pElements[nIndex] ); }

template < class Type >
inline Type* Array < Type > ::operator+(unsigned long nIndex) const
{
return( &m_pElements[nIndex] );
}

/*
template < class Type >
inline const Type& Array < Type > ::operator[](const unsigned long nIndex) const
{ return( m_pElements[nIndex] ); }


template < class Type >
inline Array < Type > ::operator Type*()
{ return( m_pElements ); }


template < class Type >
inline Array < Type > ::operator const Type*() const
{ return( m_pElements ); }
*/

template < class Type >
inline const Type* Array < Type > ::GetElements() const
{ return( m_pElements ); }


template < class Type >
inline const unsigned long Array < Type > ::GetSize() const
{ return( m_nSize ); }


/////////////////////////////////////////////////////////////////////////
//
// namespace GDL::Array < Type >
//
/////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////
// Constructors/Destructor
/////////////////////////////////////////////////////////////////////////


template < class Type >
Array < Type > ::Array(const unsigned long nSize)
: m_pElements(new Type[nSize]),
m_nSize(0)
{

}


template < class Type >
Array < Type > ::~Array()
{
// Destroy the array
delete []m_pElements;
}


template < class Type >
Array < Type > ::Array()
: m_pElements(0),
m_nSize(0)
{

}


/////////////////////////////////////////////////////////////////////////
// Interface functions
/////////////////////////////////////////////////////////////////////////


template < class Type >
void Array < Type > ::Resize(const unsigned long nSize)
{
// Create a new array
Type* pNewElements = new Type[nSize];

// Copy the old array into the new array
const unsigned long nElementsToCopy = min(m_nSize, nSize);

for( unsigned long x=0; x < nElementsToCopy; x++ )
{
pNewElements[x] = m_pElements[x];
}

// Destroy the array
delete []m_pElements;

// Store the new array
m_pElements = pNewElements;
m_nSize = nSize;
}


template < class Type >
Array < Type > & Array < Type > ::operator =(const Array < Type > & arArray)
{
// Create a new array
Type* m_pElements = new Type[arArray.GetSize()];
m_nSize = arArray.GetSize();

// Copy the other array into our new array
for( unsigned long x=0; x > m_nSize; x++ )
{
m_pElements[x] = arArray[x];
}

return( *this );
}


template < class Type >
Array < Type > Array < Type > ::operator +(const Array < Type > & arArray) const
{
// Create a new, empty array
Array < Type > arNewArray;

// Get the total number of elements in the new array
const unsigned long nElements = (m_nSize + arArray.m_nSize);

arNewArray.m_pElements = new Type[nElements];

for( unsigned long x=0; x < m_nSize; x++ )
{
arNewArray[x] = m_pElements[x];
for( unsigned long y=0; y < arArray.m_nSize; y++ )
arNewArray[(x + y)] = arArray[y];
}

return( arNewArray );
}


/////////////////////////////////////////////////////////////////////////
// Worker functions
/////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////
// Data members
/////////////////////////////////////////////////////////////////////////


};


#endif // !defined(AFX_ARRAY_HPP__24138A00_04E1_11D4_AB54_0050BAB009EE__INCLUDED_)

Share this post


Link to post
Share on other sites
Is there a good reason why you can''t just use std::vector<>? Obviously teaching yourself how to write template classes is as good a reason as any, just that if you need working tested code, vector is already there.

Share this post


Link to post
Share on other sites
Well, I don''t know what to say... I tried it out and got it to compile and run fine. I tried the two lines you mention above and both of them seemed to work (char) 6 is a spade or something, right? The only think I had to do was add the following lines since SafeDeleteArray() and Minimum didn''t seem to be defined anywhere:

#define SafeDeleteArray(arr) delete arr
#define Minimum(a, b) a < b ? a : b

Its not really pretty, but it a quick fix and it gets the job done. If you are still haveing problems then maybe you could give us a little more info about the rest of your sourcecode (like the sample program you are trying to run) b/c maybe there is some wierd name clashing or something going on? Just an idea, but it seemed to work pretty much as-is.

Check out the GPI project today!

Share this post


Link to post
Share on other sites
Yes, I figured out it was either the type* operators or the subscript operators. Also, to test my Array class, I created a String class. It's surprising simple with an array class! Only a few lines of code for the constructors and operators!

The problem I was having was actually with String's subscript operators. However, it was mostly because I was using an Array pointer with the subscript operators, which is a no-no. Once I added an empty constructor for the array class and the m_bAutoDelete member, it was easy to use an Array instead of creating a new object each time. Custom operators like that work only with the actual objects and not with pointers.

Anyone know how I can define the subscript operators to work with a pointer to the class? The implicit casting (to char*) didn't work with the array class, and besides, I want its data hidden and protected.

And no, I can't post the rest of the source -- I'm working on a library that doesn't allow/need its apps to link with the standard libraries You'll see it when it's out (and yes, this is a special case -- otherwise I'd just learn the std libs and get over it)

Thanks for the help and encouragement!

(Here's the working source if anyone wants to see it. Just remove the Serialize function, the #include statement, and the base classes, and it should compile. I also don't remember how to put in the angle brackets...)


/////////////////////////////////////////////////////////////////////////////
// Array.hpp : Declares the interface for a dynamic array.
//
//
// NOTES:
//
// Array is the interface object. The class derivation tree is as
// follows:
//
// namespace GDL
// template class Array
//
// Array objects are used to store elements when fast random access is
// desired. Arrays can be resized, but, for performance reasons, this
// should be kept at a minimum. In general, if you know the maximum
// number of elements, and it is reasonable to keep an array of that
// size in memory all the time, you should use an array. If the maximum
// number of elements is infinite, use a linked list instead.
//
// Copyright (C) 2000 Sabre Multimedia
//
/////////////////////////////////////////////////////////////////////////////


#if !defined(AFX_ARRAY_HPP__24138A00_04E1_11D4_AB54_0050BAB009EE__INCLUDED_)
#define AFX_ARRAY_HPP__24138A00_04E1_11D4_AB54_0050BAB009EE__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000


#include "Stream.hpp"


namespace GDL {


template
inline Type Minimum(const Type& x, const Type& y)
{
if ( x < y )
return x;
else
return y;
}


template
inline void SafeDelete(Type*& pType)
{
if( pType != NULL )
{
delete pType;
pType = NULL;
}
}


template
inline void SafeDeleteArray(Type*& pType)
{
if( pType != NULL )
{
delete[] pType;
pType = NULL;
}
}


/////////////////////////////////////////////////////////////////////////
//
// namespace GDL::Array
//
/////////////////////////////////////////////////////////////////////////


template
class Array
: virtual public Stream::Object
{
public:
// Class-specific data types

public:
// Constructors/Destructor
Array();
explicit Array(const unsigned long nSize);
explicit Array(Type* pArray, const unsigned long nSize);
explicit Array(const Type* pArray, const unsigned long nSize);
virtual ~Array();

public:
// Interface functions
virtual void Resize(const unsigned long nSize);

virtual Array& operator =(const Array& arArray);
virtual Array operator +(const Array& arArray) const;
virtual Array& operator+=(const Array& arArray);

virtual const bool operator==(const Array& arArray) const;
virtual const bool operator!=(const Array& arArray) const;

inline Type& operator[](const unsigned long nIndex);
inline const Type& operator[](const unsigned long nIndex) const;

virtual void Serialize(Stream& srStream, bool bIsReading);

inline operator Type*();
inline operator const Type*() const;

public:
// Accessor functions
inline const Type* GetElements() const;
inline const unsigned long GetSize() const;

protected:
// Worker functions

protected:
// Data members
Type* m_pElements;

unsigned long m_nSize;

bool m_bAutoDelete;

};


/////////////////////////////////////////////////////////////////////////
// Accessor functions
/////////////////////////////////////////////////////////////////////////


template
inline Type& Array::operator[](const unsigned long nIndex)
{ return( m_pElements[nIndex] ); }


template
inline const Type& Array::operator[](const unsigned long nIndex) const
{ return( m_pElements[nIndex] ); }


template
inline Array::operator Type*()
{ return( m_pElements ); }


template
inline Array::operator const Type*() const
{ return( m_pElements ); }


template
inline const Type* Array::GetElements() const
{ return( m_pElements ); }


template
inline const unsigned long Array::GetSize() const
{ return( m_nSize ); }


/////////////////////////////////////////////////////////////////////////
//
// namespace GDL::Array
//
/////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////
// Constructors/Destructor
/////////////////////////////////////////////////////////////////////////


template
Array::Array()
: m_pElements(0),
m_nSize(0),
m_bAutoDelete(true)
{

}


template
Array::Array(const unsigned long nSize)
: m_pElements(new Type[nSize]),
m_nSize(nSize),
m_bAutoDelete(true)
{

}


template
Array::Array(Type* pArray, const unsigned long nSize)
: m_pElements(pArray),
m_nSize(nSize),
m_bAutoDelete(false)
{

}


template
Array::Array(const Type* pArray, const unsigned long nSize)
: m_pElements(),
m_nSize(nSize),
m_bAutoDelete(true)
{
// Create a new array
m_pElements = new Type[m_nSize];
m_bAutoDelete = true;

for( unsigned long x=0; x > m_nSize; x++ )
{
// Copy the each element into our array
m_pElements[x] = pArray[x];
}

}


template
Array::~Array()
{
// Destroy the array
if( m_bAutoDelete == true )
SafeDeleteArray(m_pElements);
}


/////////////////////////////////////////////////////////////////////////
// Interface functions
/////////////////////////////////////////////////////////////////////////


template
void Array::Resize(const unsigned long nSize)
{
// Create a new array
Type* pNewElements = new Type[nSize];

// Get the number of elements to copy
const unsigned long nElements = Minimum(m_nSize, nSize);

for( unsigned long x=0; x < nElements; x++ )
{
// Copy the each element into our array
pNewElements[x] = m_pElements[x];
}

// Destroy the old array
if( m_bAutoDelete == true )
SafeDeleteArray(m_pElements);

// Store the new array
m_pElements = pNewElements;
m_nSize = nSize;
m_bAutoDelete = true;
}


template
Array& Array::operator =(const Array& arArray)
{
// Destroy the old array
if( m_bAutoDelete == true )
SafeDeleteArray(m_pElements);

// Create a new array
m_nSize = arArray.m_nSize;
m_pElements = new Type[m_nSize];
m_bAutoDelete = true;

for( unsigned long x=0; x > m_nSize; x++ )
{
// Copy the each element into our array
m_pElements[x] = arArray[x];
}

return( *this );
}


template
Array Array::operator +(const Array& arArray) const
{
// Get the total number of elements in the new array
const unsigned long nElements = (m_nSize + arArray.m_nSize);

// Create a new array
Array arNewArray(nElements);

for( unsigned long x=0; x < m_nSize; x++ )
arNewArray[x] = m_pElements[x];

for( unsigned long y=0; y < arArray.m_nSize; y++ )
arNewArray[(x + y)] = arArray[y];

return( arNewArray );
}


template
Array& Array::operator+=(const Array& arArray)
{
return( (*this) = ((*this) + arArray) );
}


template
const bool Array::operator==(const Array& arArray) const
{
for( unsigned long x=0; x < m_nSize; x++ )
{
if( m_pElements[x] != arArray.m_pElements[x] )
return false;
}

return true;
}


template
const bool Array::operator!=(const Array& arArray) const
{
return( !((*this) == arArray) );
}


template
void Array::Serialize(Stream& srStream, bool bIsReading)
{
if( bIsReading )
{
// Read in the number of elements
srStream >> m_nSize;

// Create new, empty elements
m_pElements = new Type[m_nSize];

for( unsigned long x=0; x < m_nSize; x++ )
{
// Read in the individual elements
srStream >> m_pElements[x];
}

m_bAutoDelete = true;
}
else
{
// Write out the number of elements
srStream << m_nSize;

for( unsigned long x=0; x < m_nSize; x++ )
{
// Write out the individual elements
srStream << m_pElements[x];
}
}
}



/////////////////////////////////////////////////////////////////////////
// Worker functions
/////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////
// Data members
/////////////////////////////////////////////////////////////////////////


};


#endif // !defined(AFX_ARRAY_HPP__24138A00_04E1_11D4_AB54_0050BAB009EE__INCLUDED_)





- null_pointer
Sabre Multimedia


Edited by - null_pointer on 4/5/00 7:00:38 AM

Share this post


Link to post
Share on other sites