473,387 Members | 1,575 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

Can we override [][] ?

I wanted to do an operator override for [][] but couldnt' figure out the
syntax. I tried this (code that doesn't compile commented out with //:

class CMyBitmap
{
public:
CMyBitmap( int Rows, int Columns ): Rows_( Rows ), Columns_( Columns )
{
Data_ = new SPixel[ Rows * Columns ];
}
~CMyBitmap()
{
delete[] Data_;
}

// error C2804: binary 'operator [' has too many parameters
// SPixel& operator[]( const int Row, const int Column )
// {
// return Data_[ Columns_ * Row + Column ];
// }

// error C2092: '[]' array element type cannot be function
// SPixel& operator[][]( const int Row, const int Column )

SPixel& Pixel( const int Row, const int Column )
{
return Data_[ Columns_ * Row + Column ];
}

private:
SPixel* Data_;
int Rows_;
int Columns_;

// No copy or assignment yet so disable by making private.
CMyBitmap ( CMyBitmap const& ) {};
CMyBitmap& operator=( CMyBitmap const& ) {};

};

Can we override 2d array access?
May 31 '06 #1
52 3402

"Jim Langston" <ta*******@rocketmail.com> wrote in message
news:KB***************@fe04.lga...
I wanted to do an operator override for [][] but couldnt' figure out the
syntax. I tried this (code that doesn't compile commented out with //:

class CMyBitmap
{
public:
CMyBitmap( int Rows, int Columns ): Rows_( Rows ), Columns_( Columns )
{
Data_ = new SPixel[ Rows * Columns ];
}
~CMyBitmap()
{
delete[] Data_;
}

// error C2804: binary 'operator [' has too many parameters
// SPixel& operator[]( const int Row, const int Column )
// {
// return Data_[ Columns_ * Row + Column ];
// }

// error C2092: '[]' array element type cannot be function
// SPixel& operator[][]( const int Row, const int Column )

SPixel& Pixel( const int Row, const int Column )
{
return Data_[ Columns_ * Row + Column ];
}

private:
SPixel* Data_;
int Rows_;
int Columns_;

// No copy or assignment yet so disable by making private.
CMyBitmap ( CMyBitmap const& ) {};
CMyBitmap& operator=( CMyBitmap const& ) {};

};

Can we override 2d array access?


Certainly. But...
[][] is not an operator, it's two instances of the single
operator []. If you have your operator[] do the 'right
thing', you shouldn't have any problems using expressions
such as x[], x[][], x[][][], etc. Post back if you need
more help or an example.

-Mike

May 31 '06 #2

"Mike Wahler" <mk******@mkwahler.net> wrote in message
news:5I****************@newsread2.news.pas.earthli nk.net...

"Jim Langston" <ta*******@rocketmail.com> wrote in message
news:KB***************@fe04.lga...
I wanted to do an operator override for [][] but couldnt' figure out the
syntax. I tried this (code that doesn't compile commented out with //:

class CMyBitmap
{
public:
CMyBitmap( int Rows, int Columns ): Rows_( Rows ), Columns_( Columns )
{
Data_ = new SPixel[ Rows * Columns ];
}
~CMyBitmap()
{
delete[] Data_;
}

// error C2804: binary 'operator [' has too many parameters
// SPixel& operator[]( const int Row, const int Column )
// {
// return Data_[ Columns_ * Row + Column ];
// }

// error C2092: '[]' array element type cannot be function
// SPixel& operator[][]( const int Row, const int Column )

SPixel& Pixel( const int Row, const int Column )
{
return Data_[ Columns_ * Row + Column ];
}

private:
SPixel* Data_;
int Rows_;
int Columns_;

// No copy or assignment yet so disable by making private.
CMyBitmap ( CMyBitmap const& ) {};
CMyBitmap& operator=( CMyBitmap const& ) {};

};

Can we override 2d array access?


Certainly. But...
[][] is not an operator, it's two instances of the single
operator []. If you have your operator[] do the 'right
thing', you shouldn't have any problems using expressions
such as x[], x[][], x[][][], etc. Post back if you need
more help or an example.


I had goggled for operator[] but goggle doesn't seem to index special
characters (such as '[') so the hits weren't very orderly and it took me a
long time to even find the syntax for [] My manual didn't give me any
examples, time to get a new manual.

I would need an example please, as I don't know how to override[] to accept
two paramters but you seem to indicate it is two instances of []. What is
the 'right thing' or can you direct me to a web page on the subject? As I
said, in this case Google was not my friend.
May 31 '06 #3
Jim Langston posted:

I would need an example please, as I don't know how to override[] to
accept two paramters but you seem to indicate it is two instances of
[]. What is the 'right thing' or can you direct me to a web page on
the subject? As I said, in this case Google was not my friend.

I only spent fifteen minutes on this, so it's by no means perfect.

Untested code:
class ChessBoard {
public:

class Square {
public:
enum SquareContents {
empty, pawn, castle, horse, bishop, queen, king } contents;

Square &operator=( SquareContents const sc )
{
contents = sc;
return *this;
}
};
Square squares[64];
class HorizontalCoordinate {
private:

ChessBoard &cb;
unsigned const x;

public:

HorizontalCoordinate(ChessBoard &arg_cb, unsigned const arg_x)
: cb(arg_cb), x(arg_x) {}

Square &operator[]( unsigned const y )
{
return cb.squares[ x * 8 + y ];
}
};
HorizontalCoordinate operator[](unsigned const x)
{
return HorizontalCoordinate(*this, x);
}

};

int main()
{
ChessBoard board;

board[3][5] = ChessBoard::Square::bishop;
}
As you can see, a simple member function (or even function-style
operator) would probably be better.

-Tomás
May 31 '06 #4

"Jim Langston" <ta*******@rocketmail.com> wrote in message
news:KB***************@fe04.lga...
I wanted to do an operator override for [][] but couldnt' figure out the
syntax. I tried this (code that doesn't compile commented out with //:

class CMyBitmap
{
public:
CMyBitmap( int Rows, int Columns ): Rows_( Rows ), Columns_( Columns )
{
Data_ = new SPixel[ Rows * Columns ];
}
~CMyBitmap()
{
delete[] Data_;
}

// error C2804: binary 'operator [' has too many parameters
// SPixel& operator[]( const int Row, const int Column )
// {
// return Data_[ Columns_ * Row + Column ];
// }

// error C2092: '[]' array element type cannot be function
// SPixel& operator[][]( const int Row, const int Column )

SPixel& Pixel( const int Row, const int Column )
{
return Data_[ Columns_ * Row + Column ];
}

private:
SPixel* Data_;
int Rows_;
int Columns_;

// No copy or assignment yet so disable by making private.
CMyBitmap ( CMyBitmap const& ) {};
CMyBitmap& operator=( CMyBitmap const& ) {};

};

Can we override 2d array access?


You should declare your operator as

something operator [] (int Row);

Then "something" must define

SPixel &operator [] (int Column);

The question is, what is "something"? The best thing is probably to make it
a separate class. However, a well known cheat is to make "something" an
SPixel*, which automatically provides this second operator by the usual
rules for subscripting a pointer. Hence

SPixel *operator [] (int Row) {return Row * Columns_;}

will do it!

Cy
May 31 '06 #5

Jim Langston wrote:
I wanted to do an operator override for [][] but couldnt' figure out the
syntax.


http://www.parashift.com/c++-faq-lit...html#faq-13.10

May 31 '06 #6
Tomás posted:

I only spent fifteen minutes on this, so it's by no means perfect.

Taking Cy's trick on-board, you could change it to:
class ChessBoard {
public:

class Square {
public:
enum SquareContents {
empty, pawn, castle, horse, bishop, queen, king } contents;

Square &operator=( SquareContents const sc )
{
contents = sc;
return *this;
}
};

Square squares[64];
Square *operator[](unsigned const x)
{
return squares + 8 * (x-1);
}

};

int main()
{
ChessBoard board;

board[3][5] = ChessBoard::Square::bishop;
}
-Tomás
May 31 '06 #7

"Tomás" <No.Email@Address> wrote in message
news:Tl******************@news.indigo.ie...
Jim Langston posted:

I would need an example please, as I don't know how to override[] to
accept two paramters but you seem to indicate it is two instances of
[]. What is the 'right thing' or can you direct me to a web page on
the subject? As I said, in this case Google was not my friend.

I only spent fifteen minutes on this, so it's by no means perfect.

Untested code:
class ChessBoard {
public:

class Square {
public:
enum SquareContents {
empty, pawn, castle, horse, bishop, queen, king } contents;

Square &operator=( SquareContents const sc )
{
contents = sc;
return *this;
}
};
Square squares[64];
class HorizontalCoordinate {
private:

ChessBoard &cb;
unsigned const x;

public:

HorizontalCoordinate(ChessBoard &arg_cb, unsigned const arg_x)
: cb(arg_cb), x(arg_x) {}

Square &operator[]( unsigned const y )
{
return cb.squares[ x * 8 + y ];
}
};
HorizontalCoordinate operator[](unsigned const x)
{
return HorizontalCoordinate(*this, x);
}

};

int main()
{
ChessBoard board;

board[3][5] = ChessBoard::Square::bishop;
}
As you can see, a simple member function (or even function-style
operator) would probably be better.


Thank you. Works well. This is my solution if anyone is interested.

union SPixel
{
struct {
unsigned char B, G, R, A;
};
unsigned long Value;
};

class CMyBitmap
{
public:
CMyBitmap( int Rows, int Columns ): Rows_( Rows ), Columns_( Columns )
{
Data_ = new SPixel[ Rows * Columns ];
}
~CMyBitmap()
{
delete[] Data_;
}
SPixel& Pixel( const int Row, const int Column )
{
if ( Row > Rows_ || Row < 0 )
throw std::string( "Out of bounds for row" );
else if ( Column > Columns_ || Column < 0 )
throw std::string( "Out of bounds for column" );
else
return Data_[ Columns_ * Row + Column ];
}

class HorizCoord
{
public:
HorizCoord( CMyBitmap& Bitmap, const int Row ): Bitmap_( Bitmap ),
Row_( Row ) {}
SPixel& operator[]( const int Column )
{
if ( Column > Bitmap_.Columns_ || Column < 0 )
throw std::string( "Out of bounds for column" );
else
return Bitmap_.Data_[ Bitmap_.Columns_ * Row_ + Column ];
}
private:
CMyBitmap& Bitmap_;
const Row_;
};

HorizCoord operator[] (int const Row)
{
if ( Row > Rows_ || Row < 0 )
throw std::string( "Out of bounds for row" );
else
return HorizCoord(*this, Row);
}

private:
SPixel* Data_;
int Rows_;
int Columns_;

// No copy or assignment yet so disable by making private.
CMyBitmap ( CMyBitmap const& ) {};
CMyBitmap& operator=( CMyBitmap const& ) {};

};

int main()
{
SPixel Pixel;
Pixel.Value = 0x01020304;
std::cout << "0x01020304 by color: " << (int) Pixel.A << " " << (int)
Pixel.R << " " << (int) Pixel.G << " " << (int) Pixel.B << std::endl;

CMyBitmap BitMap( 100, 100 );

BitMap.Pixel(10, 10).R = 255;
BitMap.Pixel(10, 10).B = 255;
BitMap.Pixel(10, 10).G = 255;
BitMap.Pixel(10, 10).A = 255;
std::cout << "All bits set by value: " <<BitMap.Pixel(10, 10).Value <<
std::endl;

BitMap[15][15].R = 128;
BitMap[15][15].B = 129;
BitMap[15][15].G = 130;
BitMap[15][15].A = 131;
std::cout << "Set using [][]: " << BitMap.Pixel(15, 15).Value <<
std::endl;

BitMap.Pixel(20, 20).Value = 0xFFFF0000;
std::cout << "0xFFFF0000 by color: " << (int) BitMap.Pixel(20, 20).A <<
" " << (int) BitMap.Pixel(20, 20).R << " " << (int) BitMap.Pixel(20, 20).G
<< " " << (int) BitMap.Pixel(20, 20).B << std::endl;

// Lets just prove that Intel is Bigendian.
unsigned char* pchar = reinterpret_cast<unsigned char*>(
&(BitMap.Pixel( 20, 20 ).Value ) );
std::cout << "First Byte:" << (int) *(pchar++) << std::endl;
std::cout << "Second Byte:" << (int) *(pchar++) << std::endl;
std::cout << "Third Byte:" << (int) *(pchar++) << std::endl;
std::cout << "Fourth Byte:" << (int) *pchar << std::endl;

std::string wait;
std::cin >> wait;
}
May 31 '06 #8

"Cy Edmunds" <sp***************@rochester.rr.com> wrote in message
news:Wv*****************@twister.nyroc.rr.com...

"Jim Langston" <ta*******@rocketmail.com> wrote in message
news:KB***************@fe04.lga...
I wanted to do an operator override for [][] but couldnt' figure out the
syntax. I tried this (code that doesn't compile commented out with //:

class CMyBitmap
{
public:
CMyBitmap( int Rows, int Columns ): Rows_( Rows ), Columns_( Columns )
{
Data_ = new SPixel[ Rows * Columns ];
}
~CMyBitmap()
{
delete[] Data_;
}

// error C2804: binary 'operator [' has too many parameters
// SPixel& operator[]( const int Row, const int Column )
// {
// return Data_[ Columns_ * Row + Column ];
// }

// error C2092: '[]' array element type cannot be function
// SPixel& operator[][]( const int Row, const int Column )

SPixel& Pixel( const int Row, const int Column )
{
return Data_[ Columns_ * Row + Column ];
}

private:
SPixel* Data_;
int Rows_;
int Columns_;

// No copy or assignment yet so disable by making private.
CMyBitmap ( CMyBitmap const& ) {};
CMyBitmap& operator=( CMyBitmap const& ) {};

};

Can we override 2d array access?


You should declare your operator as

something operator [] (int Row);

Then "something" must define

SPixel &operator [] (int Column);

The question is, what is "something"? The best thing is probably to make
it a separate class. However, a well known cheat is to make "something" an
SPixel*, which automatically provides this second operator by the usual
rules for subscripting a pointer. Hence

SPixel *operator [] (int Row) {return Row * Columns_;}

will do it!


This is an excellant solution, but I can't check for column overflow. I
think I'll keep the existing solution I have right now, but keep your's in
mind for other classes.

Thanks!
May 31 '06 #9

Noah Roberts wrote:
Jim Langston wrote:
I wanted to do an operator override for [][] but couldnt' figure out the
syntax.


http://www.parashift.com/c++-faq-lit...html#faq-13.10


I recommend NOT following this particular FAQ.
It uses contrive logic to support promoting the use of non-standard
syntax to reference a matrix.

I recommend using standard syntax [][] over more ambiguous ()() method.
I also recommmend using vector<vector<T> > type.

See following links for example implementations:
http://code.axter.com/dynamic_2d_array.h
http://www.codeguru.com/forum/showthread.php?t=231046
http://www.codeguru.com/forum/showth...hreadid=297838

May 31 '06 #10
Jim Langston posted:
union SPixel
{
struct {
unsigned char B, G, R, A;
};
unsigned long Value;
};

Platform-specific code, I realise. (What you're trying to do can be quite
easily achieved portably though.)
However, even if you're guaranteed that:

(1) "unsigned long" is four bytes.
(2) Your target architecture is Bigendian.

The compiler is still within its rights to put padding between any of B G
R A.

The slightly more portable solution (but still non-portable nonetheless)
would be:

struct SPixel {

unsigned long Value;

unsigned char &B, &G, &R, &A;

SPixel() :
B( reinterpret_cast<unsigned char&>(Value) ),
G( *(reinterpret_cast<unsigned char*>(&Value) + 1) ),
R( *(reinterpret_cast<unsigned char*>(&Value) + 2) ),
A( *(reinterpret_cast<unsigned char*>(&Value) + 3) )
{}
};
I'd criticise your code in a few places (in fact I'd rewrite it
altogether in a portable way), but if it gets the job done for you, then
so be it.

Expect MASSIVE problems though if you change architecture or platform.

-Tomás
May 31 '06 #11

Axter wrote:
Noah Roberts wrote:
Jim Langston wrote:
I wanted to do an operator override for [][] but couldnt' figure out the
syntax.
http://www.parashift.com/c++-faq-lit...html#faq-13.10


I recommend NOT following this particular FAQ.
It uses contrive logic to support promoting the use of non-standard
syntax to reference a matrix.


"Non-standard"? Non-standard to who? Certainly not the domain which
uses subscript notation and/or M(a,b)...or the unimplmentable M[a,b].
I recommend using standard syntax [][] over more ambiguous ()() method.
"ambiguous"? What is so special about [][] that makes it less
ambiguous than ()?
I also recommmend using vector<vector<T> > type.
Can't enforce size.
Requires dynamic allocation.
Etc...etc...

See following links for example implementations:
http://code.axter.com/dynamic_2d_array.h
Above example is horrid still. Again it may track its own size but it
neither provides bounds checking nor does it provide a client interface
to retrieve bounds so there is frankly no reason for it to track its
size at all (only m_col is used and neither are accessable). The fact
that it contains redudant check for null of a pointer wouldn't be so
bad if it wasn't being passed off as an example and didn't have so many
other problems.

As for ambiguity...the comments state that, "It's also more compatible
with a C style 2D array, in that the array is in one continuous memory
block. This makes it possible to pass this array object to a C Function
that has a C-Style 2D array for a parameter." Unfortunately it doesn't
provide an interface to retrieve the m_data field and pass it to such a
function. The only way to do it is to yet again use [] in a way that
creates icky dependencies and sets a piss poor president for future
code:

cFunThatAcceptsCStyleMatrix(matrix[0]).

This class has numerous usability problems and creates too many damn
dependencies. It looks like the code a rank beginner would come up
with, exhibiting several newbie problems, yet its being passed off as
an expert example to use contrary to a FAQ written by obvious upper
level programmers. Seems to me like you might want your ducks more in
row for such an attempt.

delete [] matrix[0]; anyone?

How about this one:

dynamic_2d_array<int> m1(5,5);
dynamic_2d_array<int> *m2 = new dynamic_2d_array<int>(m1); // perfectly
reasonable thing to do...

I don't understand the reasoning behind placing operator= under the
protected safetynet either...seems more appropriate to make private to
me. Not virtual...not useful...only dangerous.
http://www.codeguru.com/forum/showthread.php?t=231046
Also very incomplete but still offers several features yours does
not...unfortunately they work inconsistently. For example...getting
the size of a row is no problem but how to retrieve the row count??
Availability of row size is only due to return of [] . This dependency
is not necissary if the matrix class was just implemented more
completely. This version is better than the first but worse than
simply using vector<vector<T> > because it hides the encapsulating
vector for no reason and provides no access to necissary information
that vector would hold....yet exposes the internal vector to the
public...ick.

Also a rather inefficient implementation due to the reasons you
describe in the first...I agree that a single, contiguous array is much
more efficient.
http://www.codeguru.com/forum/showth...hreadid=297838


Just a repost of the first link.

I suggest that if you are going to argue with this newsgroup's faqs you
should at least provide reasonable implementations of what you deem the
correct way. The ones you have provided are dangerous, incomplete, and
useless in the real world. Again, rank beginners often come up with
better code than your first implementation (couldn't do a whole lot
worse) and could very easily do better than the second. I have to
point out these facts because with you passing it off as an example of
'correct' coding contrary to the faq I think anyone that might not
otherwise be should be made aware of the numerous flaws in your
code...of which I only touched half.

May 31 '06 #12

Tomás wrote:
int main()
{
ChessBoard board;

board[3][5] = ChessBoard::Square::bishop;
}
As you can see, a simple member function (or even function-style
operator) would probably be better.


Yes. The concept of forcing [][] on an object because it is
implemented with an array is inherently flawed. Try implementing [][]
with a bitboard for example and then compare that implementation to
functional notation.

class Board
{
private:

uint64 white_pieces;
uint64 black_pieces;
uint64 white_knights;
....
? operator[](uint row);

// easier and more appropriate:
piece pieceAt(uint row, uint col);
piece operator()(uint row, uint col);
};

There is question of how piece would be found and what it is but the
client doesn't need to worry on that. Doesn't require a bunch of extra
proxy wrappers to forcably create an unnatural syntax and doesn't clue
the client in nor cause them to depend upon the internal representation
of this Board class.

Now, in actually building a chess engine you're probably going to break
encapsulation anyway and create massive dependencies just to speed
things up a hair (if you've never done it let me tell you that a LOT of
time is spent trying to get just a little more oomph out of your
classes) but at any rate this is a perfect example of what happens when
you think, "Hey this is an array, lets make it look like one..." Well,
what happens when you decide it shouldn't be implemented with an array
anymore??

May 31 '06 #13

Noah Roberts wrote:
Tomás wrote:
int main()
{
ChessBoard board;

board[3][5] = ChessBoard::Square::bishop;
}
As you can see, a simple member function (or even function-style
operator) would probably be better.


Yes. The concept of forcing [][] on an object because it is
implemented with an array is inherently flawed. Try implementing [][]
with a bitboard for example and then compare that implementation to
functional notation.

class Board
{
private:

uint64 white_pieces;
uint64 black_pieces;
uint64 white_knights;
....
? operator[](uint row);

// easier and more appropriate:
piece pieceAt(uint row, uint col);
piece operator()(uint row, uint col);
};

There is question of how piece would be found and what it is but the
client doesn't need to worry on that. Doesn't require a bunch of extra
proxy wrappers to forcably create an unnatural syntax and doesn't clue
the client in nor cause them to depend upon the internal representation
of this Board class.

Now, in actually building a chess engine you're probably going to break
encapsulation anyway and create massive dependencies just to speed
things up a hair (if you've never done it let me tell you that a LOT of
time is spent trying to get just a little more oomph out of your
classes) but at any rate this is a perfect example of what happens when
you think, "Hey this is an array, lets make it look like one..." Well,
what happens when you decide it shouldn't be implemented with an array
anymore??


You wrote:
"but at any rate this is a perfect example of what happens when
you think, "Hey this is an array, lets make it look like one..." Well,
what happens when you decide it shouldn't be implemented with an array
anymore?? "
I must say I cannot see your point. The rational of using operator
overloading is not whether the internals of the class are with array or
something else. It is intending to make it look like array. Anyone
using C++ is accustom to using [] for accessing continues memory. This
is why you have it in std::vector and std::string but you don't at
std::list. The point is to use a code that it is easier to read. If we
were using FORTRAN then we may have preferred to using operator () and
not operator [] for subscripting. Anyways since other gave poor
implementations to the operator [] doesn't mean there are no other
better ones. You can take a look in Stroustrup's "The C++ programming
language" book for one good implementation using STL internals. There
is anther one in boost, and yet more in various matrix various
libraries (such as blitz++) and there are many more (tough I bet you
will find them flowed as well). This is programming and not
engineering!. There is no perfect solution, just a rational that you
may or may not accept. If one solution not suits you then you can find
anther that may.
Anyways - The main problem is the above code starts from the fact that
he using "C" prefixing in his class name - which is good indication
that he misses something important in programming. The second is that
this is "one time" solution - if you need 2D array and you need bit map
then first you have those two unrelated concepts be separately
implemented. From there you can continue. This may lead to the fact
that in this case you don't need "operator [] []" which I think too in
not relevant in this case.

May 31 '06 #14

<bo*******@yahoo.com> wrote in message
news:11**********************@i40g2000cwc.googlegr oups.com...

Noah Roberts wrote:
<snipping stuff unrelated to answer
Anyways - The main problem is the above code starts from the fact that
he using "C" prefixing in his class name - which is good indication
that he misses something important in programming. The second is that
this is "one time" solution - if you need 2D array and you need bit map
then first you have those two unrelated concepts be separately
implemented. From there you can continue. This may lead to the fact
that in this case you don't need "operator [] []" which I think too in
not relevant in this case.


Not this old argument again. This has been discussed many times in this
newsgroup, and different people prefer to distinguish classes from instances
in different ways. Some use capital letters for class names and small
letters for instant variables. Some use some form of prefix, some use some
formm of suffix. Some don't distinguish in anyway.

I prefer to use a prefix of 'C' Now, what is wrong with that? Where does
that break any rule of good programming?

And in this case the bitmap and the 2D array are not unrelated, because in
this case it's the only reason to allocate the memory. If I was doing the
full project (which I'm not) I'm sure I would totally refactor it and this
class would look totally different and be given a different name, and may
not actually exist.

This class was created because someone needed 2D array access to memory that
could be looked at as R,B,G,A values or all four values in one int. Which
is all this class does. How is the 2D array access and looking at R,B,G,A
values different in this particular case?
May 31 '06 #15
bo*******@yahoo.com wrote:
Anyways - The main problem is the above code starts from the fact that
he using "C" prefixing in his class name - which is good indication
that he misses something important in programming.


What is this 'something' you are referring to? And how does it
relate to using "C" as a prefix for class names?

regards
--
jb

(reply address in rot13, unscramble first)
May 31 '06 #16
Noah Roberts wrote:
Axter wrote:
Noah Roberts wrote:
Jim Langston wrote:
> I wanted to do an operator override for [][] but couldnt' figure out the
> syntax.

http://www.parashift.com/c++-faq-lit...html#faq-13.10
I recommend NOT following this particular FAQ.
It uses contrive logic to support promoting the use of non-standard
syntax to reference a matrix.


"Non-standard"? Non-standard to who? Certainly not the domain which
uses subscript notation and/or M(a,b)...or the unimplmentable M[a,b].

I recommend using standard syntax [][] over more ambiguous ()() method.


"ambiguous"? What is so special about [][] that makes it less
ambiguous than ()?
I also recommmend using vector<vector<T> > type.


Can't enforce size.
Requires dynamic allocation.
Etc...etc...

See following links for example implementations:
http://code.axter.com/dynamic_2d_array.h


Above example is horrid still. Again it may track its own size but it
neither provides bounds checking nor does it provide a client interface
to retrieve bounds so there is frankly no reason for it to track its
size at all (only m_col is used and neither are accessable). The fact
that it contains redudant check for null of a pointer wouldn't be so
bad if it wasn't being passed off as an example and didn't have so many
other problems.


The purpose of the dynamic_2d_array, is to give a dynamic version of a
static size C-style array.
It's no more or no less safer then using a static C-Style array, and
therefore, no more horrid then using a static size C-Style array.
If you need something that requires bounds checking, then you should
not use it.
The class is not intended for that purpose.
http://www.codeguru.com/forum/showthread.php?t=231046


Also very incomplete


These are example skeleton classes. They don't have to be complete.
They just need enough to get the point across as to how to get a [][]
interface.
Also a rather inefficient implementation due to the reasons you
describe in the first...I agree that a single, contiguous array is much
more efficient.
I heard this from most programmers, who don't have the experience in
actually testing this theory out.
I've conducted test, shows your above comment to be false.
Try testing this in RELEASE version, and you'll find very little
difference in performance.
In fact, some implementations have better performance with a
vector<vector< > >, then with a contiguous array.

I suggest that if you are going to argue with this newsgroup's faqs you
should at least provide reasonable implementations of what you deem the
correct way.


I suggest, that you first test your theories before making performance
claims on this newsgroup.
The implementations I posted as examples, are reasonable for their
purpose.

The ones you have provided are dangerous, incomplete, and

useless in the real world.


And again, they're no more dangerous then using static size C-Style
arrays.
It's incorrect to believe that all code requires bounds checking.
That's why the C++ standard doesn't require that STL have bounds
checking.
If' it's good for the standard, then it's good for a skeleton example
implementation.

Following an FAQ blindly, is a mistake.
This C++ FAQ is created by one person, and he is no more or no less
prone to mistakes then any other experience programmer.

IMHO, this FAQ is wrong, and I posted alternative skeleton examples
that can be used as a template for user's custom matrix class.

IMHO, your nonconstructive comments do a disservice to the C++
community and to this newsgroup.

May 31 '06 #17

Jakob Bieling wrote:
bo*******@yahoo.com wrote:
Anyways - The main problem is the above code starts from the fact that
he using "C" prefixing in his class name - which is good indication
that he misses something important in programming.


What is this 'something' you are referring to? And how does it
relate to using "C" as a prefix for class names?

regards
--
jb

(reply address in rot13, unscramble first)

The reason you can find in MFC class names prefixing with C in their
names is that when Microsoft implemented MFC namespaces were not widely
supported in many compilers. In order to have their class names unique
they used C prefix to all MFC class names. Many inexperience
programmers seeing the practices from Microsoft and following them
blindly. I believe that anyone who is doing those king if thing is
missing a key understanding in using whatever tool he/she is trying to
use.
Basically it's should bather anyone seeing others placing their own
code under namespace std just because the standard library is doing it
too
Hope that now you can understand why I think this is truly a band
practice

May 31 '06 #18

Jim Langston wrote:
<bo*******@yahoo.com> wrote in message
news:11**********************@i40g2000cwc.googlegr oups.com...

Noah Roberts wrote:
<snipping stuff unrelated to answer
Anyways - The main problem is the above code starts from the fact that
he using "C" prefixing in his class name - which is good indication
that he misses something important in programming. The second is that
this is "one time" solution - if you need 2D array and you need bit map
then first you have those two unrelated concepts be separately
implemented. From there you can continue. This may lead to the fact
that in this case you don't need "operator [] []" which I think too in
not relevant in this case.


Not this old argument again. This has been discussed many times in this
newsgroup, and different people prefer to distinguish classes from instances
in different ways. Some use capital letters for class names and small
letters for instant variables. Some use some form of prefix, some use some
formm of suffix. Some don't distinguish in anyway.

I prefer to use a prefix of 'C' Now, what is wrong with that? Where does
that break any rule of good programming?

And in this case the bitmap and the 2D array are not unrelated, because in
this case it's the only reason to allocate the memory. If I was doing the
full project (which I'm not) I'm sure I would totally refactor it and this
class would look totally different and be given a different name, and may
not actually exist.

This class was created because someone needed 2D array access to memory that
could be looked at as R,B,G,A values or all four values in one int. Which
is all this class does. How is the 2D array access and looking at R,B,G,A
values different in this particular case?


As for the C prefix see my replay to someone else bellow. As for the
Bitmap - why should we care about how do store it. You can the 2D
matrix is your own care so use it as "as - a". But more generally,
sometime in the future you will need 2D matrix for other use and then
you will simply write anther implementation of 2D matrix for this other
use. 2D matrix is one concept that can be used for many application in
which bitmap is just one of them. A good programmer will write 2D
matrix class (or better yet find good code writing by someone like the
boost people or other experience programmers) and concentrated he/her
efforts on the "real" code of the project - in this case the bit map
algorithm itself.
Good luck :)

May 31 '06 #19
FYI my own matrix class allows both syntaxes.

operator[] returns a (template) class, known either as
portable_ref_buffer or portable_cref_buffer. These are standalone
classes that are used in other places as well. Both have a pointer and
length but with portable_ref_buffer the pointer is non-const, and
portable_cref_buffer has a constructor from portable_ref_buffer. In
both cases it's a weak pointer, i.e. the class does not own the
pointer. (thus "ref" in the name, it references its memory, And
portable because it's safely portable across libraries).

portable_cref_buffer and portable_ref_buffer both have operator[]
overloaded. In both cases the overload is a const member and returns
the pointer.

Both classes have member functions begin(), end(), empty() and size()
so can be used in algorithms like for_each. begin() is guaranteed to
return a pointer so it's safe to pass to functions that require a
pointer. If empty, begin() is safe as long as you don't attempt to
dereference it.

Both classes have an implicit constructor from a vector - either a
const or non-const reference depending on which class it is. They
cannot be resized though.

May 31 '06 #20

Axter wrote:
The purpose of the dynamic_2d_array, is to give a dynamic version of a
static size C-style array.
It's no more or no less safer then using a static C-Style array, and
therefore, no more horrid then using a static size C-Style array.
Actually it is. As you said, it offers nothing over using a C array
and therefor is pointless extra code that serves no purpose.
If you need something that requires bounds checking, then you should
not use it.
The class is not intended for that purpose.
It should at least provide access to the bounds it is tracking so
clients don't have to wrap it in a class that does.
http://www.codeguru.com/forum/showthread.php?t=231046
Also very incomplete


These are example skeleton classes. They don't have to be complete.


They don't even qualify as "example skeleton classes" and that is at
least not how the first is being advertized.
They just need enough to get the point across as to how to get a [][]
interface.
In a piss poor and dangerous manner.
Also a rather inefficient implementation due to the reasons you
describe in the first...I agree that a single, contiguous array is much
more efficient.
I heard this from most programmers, who don't have the experience in
actually testing this theory out.
I've conducted test, shows your above comment to be false.


Interesting, then why do you yourself make it?

Besides, if your tests are anything like your example code then they
are completely meaningless. If they test your example code they are
equally so.
The implementations I posted as examples, are reasonable for their
purpose.
I pointed out several reasons they are not...you haven't answered those
reasons.
The ones you have provided are dangerous, incomplete, and useless in the real world.


And again, they're no more dangerous then using static size C-Style
arrays.


Correct. They are also no less so. In fact the first one provides
absolutely no benefits over a simple array whatsoever. The second
provides no benefits over vector<vector<>> and in fact removes access
to important information that would be available by just using
vector<vector<>>. Your classes are pointless at best.
It's incorrect to believe that all code requires bounds checking.
And I never said it was.
That's why the C++ standard doesn't require that STL have bounds
checking.
If' it's good for the standard, then it's good for a skeleton example
implementation.
Every single container class in the standard library has a size()
member function and in fact at least one of the containers does provide
bounds checking. Another initializes new contents on access to a non
existant index... All STL container classes also provide several
protective abstractions surrounding the internal implementation
including iterators and reference proxies. Yes, if you know what a
particular implementation looks like you can get past those as they are
only typedefs but still, it is an abstraction that can be used in a
safe and consistant manner. Your classes don't do any of these
things...your classes are sluts.

Yes, these classes are a far cry short of the STL.

Following an FAQ blindly, is a mistake.
This C++ FAQ is created by one person, and he is no more or no less
prone to mistakes then any other experience programmer.
Yes, following the FAQ blindly is a mistake. I've seen several
examples of implementing [][] that are not the newbie hackery that
yours is. I prefer to listen until I find a compelling reason not
to...your reasoning and your examples are far from compelling and in
fact are compelling arguments for the FAQ as your forcing of [][] on
this concept has led you to create monsters.
IMHO, this FAQ is wrong, and I posted alternative skeleton examples
that can be used as a template for user's custom matrix class.
Well, I've given several reasons why they don't qualify for that. They
need major revisions.

IMHO, your nonconstructive comments do a disservice to the C++
community and to this newsgroup.


You may see them as noncunstructive if you want. I am not surprised as
you continue to pass these off as "expert guidance" and so wouldn't
want to hear that they actually exemplify several horrendous beginner
mistakes but whatever.

May 31 '06 #21

Jakob Bieling wrote:
bo*******@yahoo.com wrote:
Anyways - The main problem is the above code starts from the fact that
he using "C" prefixing in his class name - which is good indication
that he misses something important in programming.
What is this 'something' you are referring to?


That your code shouldn't be depending on what type your objects are so
long as they respond to the interface you expect them to.

And how does it relate to using "C" as a prefix for class names?


C as in "this is a class" indicates that the programmer wants to know
if the types he is working with are classes or not...but his code
shouldn't care and therefore he/she shouldn't care either. Also what
happens when you decide that a class isn't the best implementation but
maybe it should just be a struct instead. You gonna change to strName
all over the damn place?

Hungarian notation is a bastard child that should have been aborted.
Too often I see code written in it where someone said, "Hey, I need
another variation of that true/false value so I'll change to char," but
then they didn't want to have to change the name all over the place so
they left it as bFlag instead of iFlag.

May 31 '06 #22
Noah Roberts wrote:
Axter wrote:

You may see them as noncunstructive if you want. I am not surprised as
you continue to pass these off as "expert guidance" and so wouldn't
want to hear that they actually exemplify several horrendous beginner
mistakes but whatever.


The example skeleton classes will remain as is, since they serve their
purpose, whether you want to believe it or not.

If you think your comments are constructive, then you're either
ignorant, or have no manners. IMHO, it's most likely both.

Good day.... I said Good day!!! ;-)

May 31 '06 #23

Axter wrote:
If you think your comments are constructive, then you're either

ignorant, or have no manners. IMHO, it's most likely both.


This is becoming too much of a flame war. But there was some
constructive criticism in there. Let me see if I can point it out:

template < class T>
class dynamic_2d_array
{
public:
dynamic_2d_array(size_t row, size_t col):m_row(row),m_col(col),
m_data((row!=0&&col!=0)?new T[row*col]:NULL){}
dynamic_2d_array(const
dynamic_2d_array&src):m_row(src.m_row),m_col(src.m _col),
m_data((src.m_row!=0&&src.m_col!=0)?new T[src.m_row*src.m_col]:NULL){
for(size_t r=0;r<m_row;++r)for(size_t c=0;c<m_col;++c) (*this)[r][c]
= src[r][c];
}
~dynamic_2d_array(){if(m_data) delete []m_data;}
inline T* operator[](size_t i) {return (m_data + (m_col*i));}
inline T const*const operator[](size_t i) const {return (m_data +
(m_col*i));}
protected:
dynamic_2d_array& operator=(const dynamic_2d_array&);
private:
const size_t m_row;
const size_t m_col;
T* m_data;
};

1. No method to retrieve back the dimensions. Easy enough to modify.
Add in:

size_t rows() const { return m_row; }
size_t cols() const { return m_col }

2. protected section when class cannot be inherited. Minor detail but
operator= is automatically disabled for this class anyway due to it
having const members.

3. no need to check for NULL in destructor

4. To access the data you call matrix[0] which is unclear notation.

5. Your copy constructor is probably slower than you think as you are
calculating the position a lot of times. But as the arrays are
identical in size you can do member-by-member copy. If you're really
advanced you'll have an is_pod<> traits-style function and use memcpy
when is_pod returns true.

I would actually say it is a bit inconsistent to allow
copy-construction but not assignment. Whilst you cannot resize,
assignment might be useful, and could be "optimised" when the two
matrices already the same dimensions by not doing a new allocation. In
fact, if the capacity of the current matrix is enough to hold the new
contents you might be able to optimise.

If you use a nested vector then resizing can be done with vector's
member resize() function.

May 31 '06 #24

Axter wrote:
Noah Roberts wrote:
Axter wrote:

You may see them as noncunstructive if you want. I am not surprised as
you continue to pass these off as "expert guidance" and so wouldn't
want to hear that they actually exemplify several horrendous beginner
mistakes but whatever.


The example skeleton classes will remain as is, since they serve their
purpose, whether you want to believe it or not.


Well, whatever. As examples on how to implement [][] I have to say
they are inadiquate and could easily lead a person down a bad path
because of what they omit. The answer is not as simple as you make it
out to be and considering it so can cause problems for people who might
listen to you. But in the end I guess they will learn the hard way. I
also used to force [][] into interfaces years ago when I was first
starting so I know the trouble they are in for. I learned, so will
they...some won't obviously.

May 31 '06 #25
Noah Roberts wrote:
"Non-standard"? Non-standard to who? Certainly not the domain which
uses subscript notation and/or M(a,b)...or the unimplmentable M[a,b].

Cute in an "oh god don't ever do that" sort of way:

struct MagicInt {
// operator overloads, constructors, etc, to make this class behave
// as an integer.
};

std::pair<MagicInt, MagicInt> operator , (const MagicInt &a, const
MagicInt& b) { return std::make_pair(a, b); }

class Array2d {
public:
value& operator[](const std::pair<MagicInt, MagicInt> &a) {
// use a.first and a.second to find the value...
}
};

int main() {
Array2d M(X, Y);

for (MagicInt a = 0; a < X; ++a)
for (MagicInt b = 0; b < Y; ++b)
M[a, b] = i + j;
}
So, 'M[a, b]' is *implementable*, even if so brittlely that you'd never
want to use it. (For instance, you cannot say 'M[1, 2]'.)

Jack Saalweachter
May 31 '06 #26

Earl Purple wrote:
Axter wrote:
If you think your comments are constructive, then you're either

ignorant, or have no manners. IMHO, it's most likely both.


This is becoming too much of a flame war.


Yes, I suppose I am being a bit agressive but I have already pointed
out these and more problems with the code he is passing off as advice.

I also think it interesting that he claims this is a "skeleton example"
yet this is the comment in the top of that file:

// dynamic_2d_array class by David Maisonave (609-345-1007)
(www.axter.com)
// Description:
// The dynamic array class listed below is more efficient then other
// similar classes that use temporary objects as return types, or use
// an std::vector as a return type.
//
// It's also more compatible with a C style 2D array, in that the
// array is in one continuous memory block. This makes it possible
// to pass this array object to a C Function that has a C-Style
// 2D array for a parameter.
// Example usage:

Doesn't look like it is thought of as a "skeleton template" to me.
Looks like it is an attempt to document a complete class. That and the
documentation even documents a feature that isn't there, namely the
retreval of the raw data storage for use in a function requiring an
array or pointer. The fact that you CAN do this is actually a bug in
the interface that can be exploited to provide functionality that
wasn't built in.

I just hate seing stuff like this passed off as expert advice
especially when he is attempting to get beginners to move contrary to
the FAQ. Sure, the FAQ could be wrong but if your going to move
against it provide something more complete, safe, and coherent. There
can be compelling reasons that [][] needs to be in the interface but
his "expert" code is not a good way to implement it and gives the
misconception that it is simple to do, and it is far from it unless you
want to stab yourself in the ass. He compares his implementation to
the STL yet it provides none of the safety features or abstractions the
STL does. It's just bad code that exhibits bad practices (as well as
being VERY difficult to read) and I think it better to point this out.

There are people I consider experts in this field and I don't always
agree with everything they say but I acknowledge they are several
levels above me. I also write questionable code and know it...but then
I'm not calling myself an expert. Axter claims to be an expert,
exclaiming how he is top rated expert this or that on website X, but
his code says otherwise.

May 31 '06 #27

Jack Saalweachter wrote:
Noah Roberts wrote:
"Non-standard"? Non-standard to who? Certainly not the domain which
uses subscript notation and/or M(a,b)...or the unimplmentable M[a,b].

Cute in an "oh god don't ever do that" sort of way:


Wow....I bow down to your abilities to spread evil. I can only hope to
be that good someday ;)

Assuming it works, and it looks to me like it would. Ouch...

May 31 '06 #28
Noah Roberts <ro**********@gmail.com> wrote:
Hungarian notation is a bastard child that should have been aborted.
Too often I see code written in it where someone said, "Hey, I need
another variation of that true/false value so I'll change to char," but
then they didn't want to have to change the name all over the place so
they left it as bFlag instead of iFlag.


I actually read an article just today on how Hungarian notation itself
has become horribly bastardized, and it is this bad version of it that
everybody knows and many people dislike. Essentially, in the original
paper, the author (Charles Simonyi) used the word "type" instead of
"kind", and people took it too literally, thus destroying the original
usefulness.

http://joelonsoftware.com/articles/Wrong.html
(near the bottom of the article)

--
Marcus Kwok
Replace 'invalid' with 'net' to reply
May 31 '06 #29

Marcus Kwok wrote:
Noah Roberts <ro**********@gmail.com> wrote:
Hungarian notation is a bastard child that should have been aborted.
Too often I see code written in it where someone said, "Hey, I need
another variation of that true/false value so I'll change to char," but
then they didn't want to have to change the name all over the place so
they left it as bFlag instead of iFlag.


I actually read an article just today on how Hungarian notation itself
has become horribly bastardized, and it is this bad version of it that
everybody knows and many people dislike. Essentially, in the original
paper, the author (Charles Simonyi) used the word "type" instead of
"kind", and people took it too literally, thus destroying the original
usefulness.

http://joelonsoftware.com/articles/Wrong.html
(near the bottom of the article)


So basically it is saying things should be named based on what their
interface is no? For instance something that is a "Copier" might be
better named as a "CopierCommand" if it was in fact a "Command".
Instances of this class should reflect what they will do.

That makes sense to me but I debate whether HN is verbose enough for
that. I also believe classes and variable names should reflect what
they are meant to do but I like to be a little more verbose about it
most of the time.

May 31 '06 #30
Marcus Kwok wrote:
I actually read an article just today on how Hungarian notation itself
has become horribly bastardized, and it is this bad version of it that
everybody knows and many people dislike. Essentially, in the original
paper, the author (Charles Simonyi) used the word "type" instead of
"kind", and people took it too literally, thus destroying the original
usefulness.

http://joelonsoftware.com/articles/Wrong.html
(near the bottom of the article)

Huh, that article totally changed my perspective on Hungarian Notation.

The idea adding type-modifiers to a language has long seemed awesome to
me; consider if (as in the example in the article above), you said:

unsafe string a = Request("name");
...
safe string b = a; // Type error; implicit conversion from 'unsafe'
to 'safe', as illegal as modifying a 'const' object.

Knowing that Hungarian Notation was /intended/ to be a work-around for
extending the type system (since it's infinitely easier and almost as
effective), rather than a simple parroting of the existing type system,
makes it potentially useful in my mind.
Jack Saalweachter
May 31 '06 #31
Earl Purple wrote:
Axter wrote:
If you think your comments are constructive, then you're either ignorant, or have no manners. IMHO, it's most likely both.


This is becoming too much of a flame war. But there was some
constructive criticism in there. Let me see if I can point it out:

template < class T>
class dynamic_2d_array
{
public:
dynamic_2d_array(size_t row, size_t col):m_row(row),m_col(col),
m_data((row!=0&&col!=0)?new T[row*col]:NULL){}
dynamic_2d_array(const
dynamic_2d_array&src):m_row(src.m_row),m_col(src.m _col),
m_data((src.m_row!=0&&src.m_col!=0)?new T[src.m_row*src.m_col]:NULL){
for(size_t r=0;r<m_row;++r)for(size_t c=0;c<m_col;++c) (*this)[r][c]
= src[r][c];
}
~dynamic_2d_array(){if(m_data) delete []m_data;}
inline T* operator[](size_t i) {return (m_data + (m_col*i));}
inline T const*const operator[](size_t i) const {return (m_data +
(m_col*i));}
protected:
dynamic_2d_array& operator=(const dynamic_2d_array&);
private:
const size_t m_row;
const size_t m_col;
T* m_data;
};

1. No method to retrieve back the dimensions. Easy enough to modify.
Add in:

size_t rows() const { return m_row; }
size_t cols() const { return m_col }


As I previously stated, the sole purpose of the dynamic_2d_array, is to
give the functionallity of a static size C-Style array that has a
dynamic size.
Since this is easy to add, IMHO, it's not needed for the example.
2. protected section when class cannot be inherited. Minor detail but
operator= is automatically disabled for this class anyway due to it
having const members. Good point.
3. no need to check for NULL in destructor Another good point.

4. To access the data you call matrix[0] which is unclear notation. I'm not sure what you mean there. Accessing an array via [][] is the
standard notation for C/C++ code.
5. Your copy constructor is probably slower than you think as you are
calculating the position a lot of times. But as the arrays are
identical in size you can do member-by-member copy. I think it would be hard to measure the perfromance difference, but
considering it could simplify the class, it would probably be a good
idea to do a std::copy instead of the two loops.
If you're really

advanced you'll have an is_pod<> traits-style function and use memcpy
when is_pod returns true.


I rather keep the class generic, and not have to rely on external
functions like boost::is_pod. I don't like creating generic code that
depends on third party libraries, even if it is boost.
You would be surprise at how many C++ developers don't even know what
boost is.
If you use a nested vector then resizing can be done with vector's
member resize() function.

I posted another link that had example code that does just that.
http://www.codeguru.com/forum/showthread.php?t=231046

The above class has a resize functoin, which I added, and it uses
vector.
I recomend using the above vector approach over my original
dynamic_2d_array class.
But if you need contiguous buffer, then the dynamic_2d_array might be a
better option.

Thanks for the constructive critique. I've already removed the op= and
the unnecessary check for NULL.

May 31 '06 #32

Axter wrote:
Thanks for the constructive critique. I've already removed the op= and
the unnecessary check for NULL.


While you're at it why don't you add some whitespace.

On the other hand...not having any definately makes your class more
obfuscated and difficult to comprehend so perhapse it is more
beneficial to beginners that you just don't. That way they won't be
able to make sense of what you are doing and will go elsewhere.

May 31 '06 #33
Tomás wrote:
Tomás posted: -snip- Taking Cy's trick on-board, you could change it to:
class ChessBoard {
public:

class Square {
public:
enum SquareContents {
empty, pawn, castle, horse, bishop, queen, king } contents;

Square &operator=( SquareContents const sc )
{
contents = sc;
return *this;
}
};

Square squares[64];
Square *operator[](unsigned const x)
{
return squares + 8 * (x-1);
}

};

int main()
{
ChessBoard board;

board[3][5] = ChessBoard::Square::bishop;
}


I didn't understood how [3][5] got converted to Square *, since it only
takes an unsigned const as argument?

First you create a ChessBoard with an empty SquareContents, I guess?

When you then assign something (bishop) to board[3][5] what happens then?

I understand "return squares" is element 0 to which you add an offset.
8*0 = 0, 8*1 = 8, 8*2 = 16, etc. How to insert a king in location 20?

I'm wondering, that perhaps it's connected with return *this from
&operator=, but it would be nice to see an explanation...?
Best regards
Martin Jřrgensen

--
---------------------------------------------------------------------------
Home of Martin Jřrgensen - http://www.martinjoergensen.dk
May 31 '06 #34
Noah Roberts <ro**********@gmail.com> wrote:
Marcus Kwok wrote:
I actually read an article just today on how Hungarian notation itself
has become horribly bastardized, and it is this bad version of it that
everybody knows and many people dislike. Essentially, in the original
paper, the author (Charles Simonyi) used the word "type" instead of
"kind", and people took it too literally, thus destroying the original
usefulness.

http://joelonsoftware.com/articles/Wrong.html
(near the bottom of the article)
So basically it is saying things should be named based on what their
interface is no?


I wouldn't necessarily say that it's based on their interface, but more
on their intent or purpose. For example, in the article he talks about
it in the context of a WYSIWYG word processor, which must distinguish
between coordinates relative to the window and coordinates relative to
the page layout. Prefixes start with either 'x' or 'y' (indicating
horizontal or vertical coordinate) and either 'l' or 'w' (for "layout"
or "window", respectively). Another common prefix is 'c' for "count",
so a prefix of "cb" would indicate that this variable is used to count
bytes.

Then, if anywhere in your code you see a "xl = yw" or a "yl = cb", it
should tell you that you're trying to mix logically different types,
even though all of them may be implemented as ints.
For instance something that is a "Copier" might be
better named as a "CopierCommand" if it was in fact a "Command".
Instances of this class should reflect what they will do.
I don't think this is quite the idea.
That makes sense to me but I debate whether HN is verbose enough for
that. I also believe classes and variable names should reflect what
they are meant to do but I like to be a little more verbose about it
most of the time.


--
Marcus Kwok
Replace 'invalid' with 'net' to reply
May 31 '06 #35
Martin Jřrgensen wrote:
I didn't understood how [3][5] got converted to Square *, since it only
takes an unsigned const as argument?


This trick goes back a way to a standard programming trick they teach in
schools (which isn't actually useful, but kind of clever).

If you tell students in their first C programming class, "dynamically
create a 2-d array, with size NxM", they'll do one of the following:

char **array = malloc(N * sizeof(char*));
for (int i = 0; i < N; ++i) {
array[i] = malloc(M * sizeof(char));
}

and then access the array by saying 'array[i][j]'.

or

char *array = malloc(N * M * sizeof(char));

and then access the array by saying 'array[i*M + j]'.
In their second-year programming class, the students learn a trick, and
they'll write the following:

char *flatArray = malloc(N * M * sizeof(char));
char **array = malloc(N * sizeof(char*));
for (int i = 0; i < N; ++i) {
array[i] = flatArray + i*M;
}

and then access the array by saying 'array[i][j]'.

This combines the advantages of the first two ways: you have the easy
access of the first way ('array[i][j]'), but when it comes time to clean
up, you only have to free the two arrays (flatArray and array). In the
first way, you had to remember to free all of the rows of the array; if
you just say 'free(array)', you leak them.

(The third year student would skip the extra variable 'flatArray', and
just allocate the space in array[0]; the fourth year student would say,
"Why the hell do I need a 2d array?")
This C++ trick is really just the equivalent of the second-year C
student's trick. However, instead of storing the second char** array
internally, it creates entries from it whenever you ask for them.
Jack Saalweachter
May 31 '06 #36
Jack Saalweachter <sa**********@purdue.edu> wrote:
Marcus Kwok wrote:
I actually read an article just today on how Hungarian notation itself
has become horribly bastardized, and it is this bad version of it that
everybody knows and many people dislike. Essentially, in the original
paper, the author (Charles Simonyi) used the word "type" instead of
"kind", and people took it too literally, thus destroying the original
usefulness.

http://joelonsoftware.com/articles/Wrong.html
(near the bottom of the article)
Huh, that article totally changed my perspective on Hungarian Notation.


Yeah, me too, because before I saw this article I only knew about the
less-useful "Systems Hungarian" as opposed to the more useful "Apps
Hungarian", and thus had already discarded "[Systems] Hungarian
Notation" as not very useful.
The idea adding type-modifiers to a language has long seemed awesome to
me; consider if (as in the example in the article above), you said:

unsafe string a = Request("name");
...
safe string b = a; // Type error; implicit conversion from 'unsafe'
to 'safe', as illegal as modifying a 'const' object.

Knowing that Hungarian Notation was /intended/ to be a work-around for
extending the type system (since it's infinitely easier and almost as
effective), rather than a simple parroting of the existing type system,
makes it potentially useful in my mind.


Yes, I never really saw the value in most situations of specifying the
specific type of a variable either. The intended use gives you much
greater information.

--
Marcus Kwok
Replace 'invalid' with 'net' to reply
May 31 '06 #37
Jack Saalweachter wrote:
Martin Jřrgensen wrote: -snip-
This C++ trick is really just the equivalent of the second-year C
student's trick. However, instead of storing the second char** array
internally, it creates entries from it whenever you ask for them.


You didn't really answer my questions. I think location 20 would be
[3][4] since that looks like *(squares + 8 * 2)[4], but I just wanted to
be sure.
Best regards
Martin Jřrgensen

--
---------------------------------------------------------------------------
Home of Martin Jřrgensen - http://www.martinjoergensen.dk
May 31 '06 #38
Martin Jřrgensen wrote:
You didn't really answer my questions. I think location 20 would be
[3][4] since that looks like *(squares + 8 * 2)[4], but I just wanted to
be sure.

You are correct: I completely misunderstood what you were asking.

Deep down, it shouldn't matter how you access location 20; what gets
mapped to location 20 is effectively 'implementation defined'. The goal
of the chessboard class is to abstract away the array and just give you
array-like access; if you can say 'board[3][4]' to refer to a location
on the board, why would you ever want to try to refer to location 20 in
the underlying array?

Just to be mean, the chessboard class could implement its op[] like so:

Square *operator[](unsigned const x)
{
return squares + 8 * (8 - x - 1);
}

From the outside, the chessboard behaves the same; however, location 20
is no longer mapped to board[3][4].
Jack Saalweachter
May 31 '06 #39
Martin Jřrgensen posted:

board[3][5] = ChessBoard::Square::bishop;

I didn't understood how [3][5] got converted to Square *, since it only
takes an unsigned const as argument?

Analyse the following statement:
board[3][5] = ChessBoard::Square::bishop;
If you look up an operator precedence table, you'll see that it's
identical to:
( board[3] )[5] = ChessBoard::Square::bishop;
It's plain to see that operator[] is applied to "board". If we look at
the definition of this member function, we see that it returns a Square*,
i.e. a pointer. So it becomes:

(p)[5] = ChessBoard::Square::bishop;
When you apply [] to an intrinsic type, it evaluates to:
*(p + 5) = ChessBoard::Square::bishop;
So, looking at it again from the start:

board[3] evaluates to a pointer to a Square.
The block brackets are then applied to the pointer in order to access
an element at a particular index relative to the original pointer value.
-Tomás
Jun 1 '06 #40
Tomás schrieb:
Jim Langston posted:

union SPixel
{
struct {
unsigned char B, G, R, A;
};
unsigned long Value;
};
Platform-specific code, I realise. (What you're trying to do can be quite
easily achieved portably though.)
However, even if you're guaranteed that:

(1) "unsigned long" is four bytes.
(2) Your target architecture is Bigendian.

The compiler is still within its rights to put padding between any of B G
R A.


The OP seems to operate on a little endian machine.

He (Jim Langston) wrote: // Lets just prove that Intel is Bigendian.


I hope the code does not depend on it. :-)

Thomas
Jun 1 '06 #41

Jack Saalweachter wrote:
struct MagicInt {
// operator overloads, constructors, etc, to make this class behave
// as an integer.
};

std::pair<MagicInt, MagicInt> operator , (const MagicInt &a, const
MagicInt& b) { return std::make_pair(a, b); }

class Array2d {
public:
value& operator[](const std::pair<MagicInt, MagicInt> &a) {
// use a.first and a.second to find the value...
}
};

int main() {
Array2d M(X, Y);

for (MagicInt a = 0; a < X; ++a)
for (MagicInt b = 0; b < Y; ++b)
M[a, b] = i + j;
}
So, 'M[a, b]' is *implementable*, even if so brittlely that you'd never
want to use it. (For instance, you cannot say 'M[1, 2]'.)

Jack Saalweachter


Submit that to boost - all you have to do is implement MagicInt and it
will probably become part of their "not so important" libraries. (A bit
like lambda)

Jun 1 '06 #42
Tomás wrote:
Martin Jřrgensen posted:
board[3][5] = ChessBoard::Square::bishop;

I didn't understood how [3][5] got converted to Square *, since it only
takes an unsigned const as argument?


Analyse the following statement:
board[3][5] = ChessBoard::Square::bishop;
If you look up an operator precedence table, you'll see that it's
identical to:
( board[3] )[5] = ChessBoard::Square::bishop;
It's plain to see that operator[] is applied to "board". If we look at
the definition of this member function, we see that it returns a Square*,
i.e. a pointer. So it becomes:

(p)[5] = ChessBoard::Square::bishop;
When you apply [] to an intrinsic type, it evaluates to:
*(p + 5) = ChessBoard::Square::bishop;
So, looking at it again from the start:

board[3] evaluates to a pointer to a Square.
The block brackets are then applied to the pointer in order to access
an element at a particular index relative to the original pointer value.


Thanks - I also thought it must be something like this....

Just another little thing:

Square &operator=( SquareContents const sc ) didn't have to return *this
for the program to work, did it?

I guess the reason for having "return *this" is that you can then do
something like (not that it might be a good idea here, but isn't it
possible):

ChessBoard b1, b2, b3;

b1[3][5] = b2[0][4] = b3[3][3] = ChessBoard::Square::bishop;

?
Best regards
Martin Jřrgensen

--
---------------------------------------------------------------------------
Home of Martin Jřrgensen - http://www.martinjoergensen.dk
Jun 1 '06 #43
Jack Saalweachter wrote:
Martin Jřrgensen wrote:
You didn't really answer my questions. I think location 20 would be
[3][4] since that looks like *(squares + 8 * 2)[4], but I just wanted
to be sure.
You are correct: I completely misunderstood what you were asking.

Deep down, it shouldn't matter how you access location 20; what gets
mapped to location 20 is effectively 'implementation defined'. The goal
of the chessboard class is to abstract away the array and just give you
array-like access; if you can say 'board[3][4]' to refer to a location
on the board, why would you ever want to try to refer to location 20 in
the underlying array?


Nobody wants that. It's just a matter of understanding the code.
Just to be mean, the chessboard class could implement its op[] like so:

Square *operator[](unsigned const x)
{
return squares + 8 * (8 - x - 1);
}

From the outside, the chessboard behaves the same; however, location 20
is no longer mapped to board[3][4].


That doesn't give any sense.

You changed:

"return squares + 8 * (x-1)" -> "return squares + 8 * (7 - x)"

Original case: x = 2 => 8, your case: x = 2 => 40.

What are you trying to do?
Best regards
Martin Jřrgensen

--
---------------------------------------------------------------------------
Home of Martin Jřrgensen - http://www.martinjoergensen.dk
Jun 1 '06 #44
Martin Jřrgensen posted:

Square &operator=( SquareContents const sc ) didn't have to return
*this for the program to work, did it?

Not it didn't need to return a reference to itself, we could have had:

void &operator=( ...

But that wouldn't be very C++-like, because an assignment results in an
L-value in C++, e.g.:

a = b = c;
Just for some trivia, an assignment results in an R-value in C, so the
following is illegal in C:
a = b = c;

I guess the reason for having "return *this" is that you can then do
something like (not that it might be a good idea here, but isn't it
possible):

ChessBoard b1, b2, b3;

b1[3][5] = b2[0][4] = b3[3][3] = ChessBoard::Square::bishop;

Exactly.
-Tomás
Jun 1 '06 #45
Tomás schrieb:
Martin Jřrgensen posted:
Square &operator=( SquareContents const sc ) didn't have to return
*this for the program to work, did it?
Not it didn't need to return a reference to itself, we could have had:

void &operator=( ...


void operator=( ...

But that wouldn't be very C++-like, because an assignment results in an
L-value in C++, e.g.:

a = b = c;
Just for some trivia, an assignment results in an R-value in C,
correct.
... so the following is illegal in C:
a = b = c;


Did you try it?

Thomas
Jun 1 '06 #46

Thomas J. Gritzan wrote:
Tomás schrieb:

... so the following is illegal in C:
a = b = c;


Did you try it?


Probably not since last I used C that kind of code was rampant. I do
this often:

int a, b, c;

a = b = c = 0;

Of course not exactly in cases like that since it is better to
initialize than assign, even if it requires a few more characters be
typed, but on reassignment that often is done and perfectly valid in C
as well as C++.

Jun 1 '06 #47

bo*******@yahoo.com wrote:
Noah Roberts wrote:
Yes. The concept of forcing [][] on an object because it is
implemented with an array is inherently flawed. Try implementing [][]
with a bitboard for example and then compare that implementation to
functional notation.

class Board
{
private:

uint64 white_pieces;
uint64 black_pieces;
uint64 white_knights;
....
? operator[](uint row);

// easier and more appropriate:
piece pieceAt(uint row, uint col);
piece operator()(uint row, uint col);
};

Now, in actually building a chess engine you're probably going to break
encapsulation anyway and create massive dependencies just to speed
things up a hair (if you've never done it let me tell you that a LOT of
time is spent trying to get just a little more oomph out of your
classes) but at any rate this is a perfect example of what happens when
you think, "Hey this is an array, lets make it look like one..." Well,
what happens when you decide it shouldn't be implemented with an array
anymore??


I must say I cannot see your point. The rational of using operator
overloading is not whether the internals of the class are with array or
something else. It is intending to make it look like array.


The point is that in imposing the array semantics on the above board
object you have created a depenency on the internals. It would be
difficult and inefficient to implement that interface with a
bitboard...if you doubt that then try it.

Anyone using C++ is accustom to using [] for accessing continues memory.
Using objects is about abstraction.

This is why you have it in std::vector and std::string but you don't at
std::list.


Conceptually both vector and string are arrays. That is the
abstraction they are. Board, Matrix, etc...are all abstractions above
that. You can argue that a 2d array in fact is conceptually an array
and this would be correct but there are two things to consider. First,
implementing that correctly is not as simple as creating some storage
medium and then exposing it to the public. You need abstractions or
you are better off with the more natural primative type itself. The
second thing to consider is that you already have 1d arrays that can,
used together, do everything you might need of a 2, 3, 4, etc dim
array. In an effort to use the simplest method to get the job you need
done why reinvent the wheel for each dimension? Why not use the tools
at your disposal that do the job you need done?

At any rate...Board and Matrix as types or abstractions are NOT arrays.
I gave a perfect example of why pretending they are is a problem...A
board and matrix both have two dimensional coordinates and have an
"area" but they are an abstraction above array and thus shouldn't have
array semantics imposed upon them - they could use an array inside but
shouldn't expose that to the outside in any way, including especially
their own interface. I would argue that the same is true for the OP's
bitmap class.

Jun 1 '06 #48
Noah Roberts wrote:
Thomas J. Gritzan wrote:
Tomás schrieb:


... so the following is illegal in C:
a = b = c;


Did you try it?

Probably not since last I used C that kind of code was rampant. I do
this often:

int a, b, c;

a = b = c = 0;

Of course not exactly in cases like that since it is better to
initialize than assign, even if it requires a few more characters be
typed, but on reassignment that often is done and perfectly valid in C
as well as C++.

How would L-versus-R-values enter into it?

Because of right associativity, 'a = b = c = 0;' is evaluated as 'a = (b
= (c = 0));' in either language, so regardless of whether assignment
results in an R-value or an L-value, the result of assignment is only
being used as an R-value.
Jack Saalweachter
Jun 1 '06 #49

Jack Saalweachter wrote:
Noah Roberts wrote:
Thomas J. Gritzan wrote:
Tomás schrieb:


... so the following is illegal in C:
a = b = c;

Did you try it?

Probably not since last I used C that kind of code was rampant. I do
this often:

int a, b, c;

a = b = c = 0;

Of course not exactly in cases like that since it is better to
initialize than assign, even if it requires a few more characters be
typed, but on reassignment that often is done and perfectly valid in C
as well as C++.

How would L-versus-R-values enter into it?

Because of right associativity, 'a = b = c = 0;' is evaluated as 'a= (b
= (c = 0));' in either language, so regardless of whether assignment
results in an R-value or an L-value, the result of assignment is only
being used as an R-value.


Yep, that would be the reason why it works just fine.

Jun 1 '06 #50

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: Woodmon | last post by:
Example of my CSS follows: <style type="text/css" media="screen"> BODY { color: white } A:link { color: 66CCFF; } A:visited { color: CC66FF; } A:active { color: CC66FF; } A:hover {...
0
by: Craig Schneider | last post by:
// Is there any way to override the XML Serialization of the following SimpleClass // to turn off the DefaultValue of a boolean? Sure, I can override the DefaultValue from // true to false, but...
7
by: Dave Y | last post by:
I am a newbie to C# and am having trouble trying to override a ListView property method. I have created a new class derived from the Forms.Listview and I cannot figure out the syntax to override...
5
by: Mark Broadbent | last post by:
Oh yes its that chestnut again! Ive gone over the following (http://www.yoda.arachsys.com/csharp/faq/ -thanks Jon!) again regarding this subject and performed a few of my own tests. I have two...
2
by: Flip | last post by:
In java, the default for methods is override. In c# that is not the case. This talks about two classes, the base class and the overriding class. What happens when you have a third class in the...
5
by: Stoyan | last post by:
Hi All, I don't understand very well this part of MSDN: "Derived classes that override GetHashCode must also override Equals to guarantee that two objects considered equal have the same hash code;...
15
by: John Salerno | last post by:
Hi all. I have a question about virtual and override methods. Please forgive the elementary nature! First off, let me quote Programming in the Key of C#: "Any virtual method overridden with...
2
by: Adriano Coser | last post by:
Hello. After I converted my .net code to the new VC2005 syntax I started to get C4490 on my ExpandableObjectConverter subclass overrides. The GetProperties method is no longer called by the...
8
by: bdeviled | last post by:
I am deploying to a web environment that uses load balancing and to insure that sessions persist across servers, the environment uses SQL to manage sessions. The machine.config file determines how...
5
by: Marcel Hug | last post by:
Hi NG ! I'm new in C# and I'm reading a book about the fundamentals and concepts. In the chapter Methods it's written to use virtual, if i would like to override the method in a subclass. This...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.