Archived

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

DJSnow

*argh* me, and my [] overloading problem on pointers

Recommended Posts

DJSnow    100
hi. great, perhaps i''m to dumb to figure this out, or... don''t what''s wrong today: i have overloaded the "[]" operator exactly, for my buffer class. it works, if i do:
BufferClass MyBuffer;
MyBuffer.Create( 100 ); // create with 100 elements
MyBuffer[10] = 10;
MyBuffer[99] = 5;
// and so on
 
BUT, if i do:
BufferClass *MyBuffer; //pointer now !!
MyBuffer = new BufferClass( 100 ); // elements in constructor this time !
MyBuffer[10] = 10;
MyBuffer[99] = 10;
 
as you can guess, the second way with the pointer don''t work - because, the compiler sees this as a pointer to, and if i do MyBuffer[10] it looks up ten pointer-sizes away and is doing there the insert - protection fault !!! how the f****** hell do i have to overload my operators that this works ??? DJSnow --- this post is manually created and therefore legally valid without a signature

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
You need to dereference your pointer... something like this:

(*MyBuffer)[10] = 10;
(*MyBuffer)[99] = 10;


or

BufferClass& bc = *MyBuffer;
bc[10] = 10;
bc[99] = 10;

Share this post


Link to post
Share on other sites
DJSnow    100

no - that''s impossible !
this is goofy, looks ugly and is totally inapropriate.

there must be another way to do this !?

(except the "SetValueAt( index, value )" function!)

any other hints ??


DJSnow
---
this post is manually created and therefore legally valid without a signature

Share this post


Link to post
Share on other sites
Yratelev    130
Maybe... and this is a maybe dont get ur hopes up...

friend void BufferClass::operator [] ( BufferClass*, int);

Not an expert, so the first half might be wrong, but the idea is 2 arguments, not just int?

hope it at least points (not pun intended) you in the right direction.

Stu

Share this post


Link to post
Share on other sites
Mayrel    348
You don''t. You have to dereference the pointer.

You cannot overload operator[] (BufferClass *, int) because operator[] is required to be a member function.

Even if you could, what would you do if you ever wanted to maintain an array of BufferClass objects? You wouldn''t be able to.

CoV

Share this post


Link to post
Share on other sites
DJSnow    100
@mayrel:

>>maintain an array of BufferClass objects?

no - i don't want to hold an array - that's the point !
i'd like to have the class instanced via:

BufferClass *MyBuffer = new BufferClass( 100 );

and then to access each element of the buffer via MyBuffer[x].
you are right, yes !


@Yratelev:
>>but the idea is 2 arguments, not just int?
mmh....dunno, to be honest - are the the parameters of "
MyBuffer[25] = 10 
"
handled as the two parameters of the operator [] ?
sorry, i haven't stepped so deep into operator-overloading. so i may seem a bit "unhelped"

DJSnow
---
this post is manually created and therefore legally valid without a signature

[edited by - DJSnow on January 23, 2004 3:40:19 PM]

Share this post


Link to post
Share on other sites
Sneftel    1788
You cannot do it. What you're trying to do is replace the default behavior of pointers in C++, and you're not allowed to do that.

Your choices are:

(*MyBuffer)[10] = 10;
or
MyBuffer->operator[](10) = 10;
Your choice.

Also, I think it's possible that you're confused about how constructors work, since your comment seems to indicate that you think constructor arguments can only be passed to new. This code works fine:


BufferClass MyBuffer(100); // elements in constructor this time !
MyBuffer[10] = 10;
MyBuffer[99] = 10;


"Sneftel is correct, if rather vulgar." --Flarelocke

[edited by - sneftel on January 23, 2004 3:44:59 PM]

[edited by - sneftel on January 23, 2004 3:46:54 PM]

Share this post


Link to post
Share on other sites
rypyr    252
You cannot explicitly do what you want to do...that''s the way the language is. You realize that operator overloading is just syntactic sugar, right?

If, for some reason, you HAVE to use a pointer (maybe it''s a class member and you don''t know the size upon the class'' creation? maybe you want to ensure it''s on the heap??) and you REALLY WANT to use the [] notation without a lot of ughly notation, then I would just use a reference as already stated...

For the ultimate in indirection, you could wrap up the pointer in another class that has operator[] defined and forwards all calls to the operator[] to the pointer''s operator[]. Very silly though just for some nice syntax:


class BufferPointer {
protected:
BufferClass* m_pBuff;
void copy(const BufferPointer& o) {
if(o != this) {
if(m_pBuff) delete m_pBuff;
m_pBuff = new BufferClass(o.m_pBuff); // assumes deep copy for BufferClass

}
}
public:
BufferPointer() : m_pBuff(0) {}
BufferPointer(int size) {
m_pBuff = new BufferClass(size);
}
explicit BufferPointer(BufferClass* pBuf) {
if(m_pBuff) delete m_pBuff;
m_pBuff = pBuf;
}
BufferPointer(const BufferPointer&) {
copy(o);
}
BufferPointer& operator=(const BufferPointer& o) {
copy(o);
return *this;
}
virtual ~BufferPointer() { delete m_pBuff; }
int& operator[](unsigned int i) { assert(m_pBuff); return (*m_pBuff)[i]; }
};

class OtherClass {
BufferPointer buf;
void func() {
buf = BufferPointer(new BufferClass(100));


buf[10] = 5;
}
};

Share this post


Link to post
Share on other sites
rypyr    252
P.S. This is why I never found overloading operators was a great solution. It''s often easier just to use an at() function...it''s a small name and looks just fine to me:


template
class BufferClass {
T* array;
public:
BufferClass(unsigned int size) { array = new T[size]; }
virtual ~BufferClass() { delete array; }

T& at(unsigned int index) { return array[index]; }
};

BufferClass* pbuf = new BufferClass(100);
pbuf->at(5) = 8;


Regards,
Jeff

Share this post


Link to post
Share on other sites
Mayrel    348
quote:
Original post by DJSnow
no - i don''t want to hold an array - that''s the point !


You may wish to in the future.
quote:

i''d like to have the class instanced via:

BufferClass *MyBuffer = new BufferClass( 100 );

and then to access each element of the buffer via MyBuffer[x].
you are right, yes !


I can see what you want to do, but you can''t do that. At all. Ever.
quote:

mmh....dunno, to be honest - are the the parameters of "
MyBuffer[25] = 10  
"
handled as the two parameters of the operator [] ?
sorry, i haven''t stepped so deep into operator-overloading. so i may seem a bit "unhelped"


No, operator[] accepts only one argument, which is the index. If it returns a reference to the selected element, then you can set that element with =. If it doesn''t return a reference, then you can''t set it with =.

CoV

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
Goofball, just listen to me, the first replier, and don''t ask questions.

If you don''t like the answer, then don''t user pointers.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
Ok, here''s another thing you can do. But probably still ugly, since you seem to want to change the language and didn''t like my original reply:

MyBuffer[0][10] = 10;
MyBuffer[0][99] = 10;

There, happy?

Share this post


Link to post
Share on other sites
hplus0603    11356
You can''t overload built-in operators for built-in types. All pointers are built-in types. Thus, you can''t do what you want.

However, you can declare a BufferPtr type which inside contains a Buffer *, but which overloads operator[]. Something like:


class BufferPtr {
public:
BufferPtr( Buffer * b ) : b_( b ) {}
BufferPtr & operator=( Buffer * b ) { b_ = b; }
operator Buffer *() { return b_; }
Element & operator[]( int ix ) { return (*b_)[ix] );
};


Note that this is the smallest-possible implementation, if you want things like reference counting and templating, that''s a little more code, but not much. Then you can write code like so:


BufferPtr bp = new Buffer();
bp[3] = 5;


Note that wanting to overload operators on a pointer typically means that you haven''t quite understood what makes C++ "tick" yet, and you should either stick with C#/Java, or understand better whey they say that C++ is "statically typed" and uses "value composites".

Share this post


Link to post
Share on other sites
Xai    1848
To the OP, what you are trying to do is completely broken

You have overloaded the operator for your class, so it works in all cases where people have instances of your class.

Now you have absolutely no control over operators defined on other types and builtins, and arrays and pointers are builtins ...

If your user declares an object of your class type, then they can use your operators, if they declare a pointer, then they must dereference it and THEN they can use your functions and operators, and if the declare an array of your objects, they must dereference it then use your class.

ie, if they have an array:

MyClass objects[10];

and they wanted to do something with the third item inside each of your objects, it would be:

for(int i = 0; i < 10; ++i)
objects[2];

or

for(MyClass *curr=objects; curr < &object[10]; ++curr)
(*curr)[2];

Share this post


Link to post
Share on other sites
rypyr    252
quote:
Original post by hplus0603
However, you can declare a BufferPtr type which inside contains a Buffer *, but which overloads operator[]. Something like:



Which is what I wrote and laid out code several posts earlier ...

Xai, next time don''t use i as your index as it''s getting formatted into italics for your post...

Let''s kill this thread now, since we''re all re-hashing the same thing.

Regards,
Jeff

Share this post


Link to post
Share on other sites
Fruny    1658
Buffer* ptr = new Buffer(100);
Buffer& ref = *ptr;
ref[25] = 10;

done.


“Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.”
— Brian W. Kernighan (C programming language co-inventor)

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
quote:
Original post by rypyr
quote:
MyBuffer[0][10] = 10;
MyBuffer[0][99] = 10;

There, happy?



Tricky...but dangerous...


You can live on the edge when you know what you''re doing. ;-)

Of course, I''d never program this way.

As to the original poster of the question, pass your pointer to the buffer class to a function as a dereferenced pointer and then inside the function you can do MyBuffer[10] = 10 or MyBuffer[99] = 10 to your heart''s content.

Example:

void Func(BufferClass& MyBuffer)
{
MyBuffer[10] = 10;
MyBuffer[99] = 10;
}

Func(*MyBuffer);


OR, you can make a template to auto-dereference your pointer:

template <typename T>
T& Ref(T* ptr)
{
return *ptr;
}

and call this like:
Ref(MyBuffer)[10] = 10;
Ref(MyBuffer)[99] = 10;

(A smart C++ compiler should be able to handle this syntax instead of typing Ref<BufferClass>(MyBuffer)[10] = 10; )

Why anyone would waste the time to do this is beyond me, but my point is there are 1000 ways to skin a cat in C++.

---------------------------
So, your choices are:

1) (*MyBuffer)[10] = 10; (The one I''d probably use in a lot of cases)

2) BufferClass& bc = *MyBuffer; bc[10] = 10; (Would use if I get tired of typeing and bc was used a lot)

3)
template <typename T>
T& Ref(T* ptr)
{
return *ptr;
}
Ref(MyBuffer)[10] = 10;

(Would use If I like to type a lot)

4) MyBuffer[0][10] = 10;
(Would use if I wanted to live on the edge.)

5) MyBuffer->operator[](10) = 10;
(You probably wouldn''t see this in my code since it''s even more to type.)

6) Have an ''At'' member function:
MyBuffer->At(10) = 10;
(May use if ''At'' is a virtual function and my subclasses do some additional stuff or ''At'' is used for bounds checked indexing and operator[] is reserved for no bounds checking, or operator[] calls virtual ''At'' so that I can use operator[] in subclasses but am dereferencing a base class pointer)

7) Have some strange dereferencing function (basically specialized version of above template):
BufferClass& Ref(BufferClass* ptr)
{
return *ptr;
}

Ref(MyBuffer)[10] = 10;
(This garbage wouldn''t be in my code because I can use the above template instead.)

8) Use a macro (obviously I''m running out of examples):
#define Ref(_x) (*(_x))

Ref(MyBuffer)[10] = 10;

(Would not be in my code.)


9) Anyone think of anything I missed?

Share this post


Link to post
Share on other sites
DJSnow    100
@anonymous poster:
a nice sum-up !

@all:
ok, you have convinced me - i''ll use an "at()" function.

thanks for the replies.


DJSnow
---
this post is manually created and therefore legally valid without a signature

Share this post


Link to post
Share on other sites
Mayrel    348
quote:
Original post by Anonymous Poster
You could do:


*(MyBuffer+10)=10;
*(MyBuffer+99)=10;



He could, but that wouldn''t be what he wanted.

CoV

Share this post


Link to post
Share on other sites