Skip to main content
gamedev.net
🔒 Locked

Overloading operator - in C++

Started by sipickles Mar 24, 2007 at 10:26 AM 12 replies 2.1k views
Original Post
sipickles
sipickles
Hello, After seeing it done in Boost::smart_ptr, I decided it would be helpful to overload the -> operator in a few of my classes. For example, my CEffect class is a wrapper for ID3DXEffect interface. At present, I have been having to use the effect like this:

LPD3DXEFFECT CEffect::GetEffect( void )
{
	return  m_effect;
}

/////////////////////////////////////////////////

m_effect->GetEffect()->SetMatrix("World", &temp );

I hoped I could do this too:

LPD3DXEFFECT CEffect::operator->( void )
{
	return  m_effect;
}

/////////////////////////////////////////////////

m_effect->SetMatrix("World", &temp );

... but it doesn't seem to work. I am sure I am doing something simple wrong. Any advice gratefully received. Simon
Omid Ghavami
Omid Ghavami
Hmm, I don't know. It just doesn't seem like such a great idea. In the case of Boost's smart pointers, it's still intuitive. But in this case it would be very confusing to overload that operator.
Anyhow it seems like you need to return a pointer (or some other class overriding the -> operator), so that the -> is a valid operation on the return type.

Best regards, Omid
rip-off
rip-off
m_effect is a pointer, so you need to dereference the pointer to call CEffect::operator->(), which you overloaded:

(*m_effect)->...
sipickles
sipickles
Hmm, no, thats not quite it.

The overloading compiles fine.

When using the effect, Thats where it complains. Here's it written another way:

class CEffect{    CEffect( char* filename ) { m_fx = NULL ; D3DXCreateEffectFromFile( filename, m_fx, .....etc); }    ~CEffect() { SAFE_RELEASE( m_fx ); }    ID3DXEffect* m_fx;public:        ID3DXEffect* operator->() { return m_fx; }//..... other functionality}CEffect* m_effect = new CEffect("fire.fx");m_effect->SetMatrix("World", worldMatrix);///////////////////////////////////////// Outputerror C2039: 'SetMatrix' : is not a member of 'CEffect'


Does that make it any clearer?

Thanks

Simon
Agony
Agony
Boost smart pointers are actual instances of objects, not pointers. Your m_effect variable in your last example is a raw pointer to a CEffect instance. Which means that the -> operator applies to the raw pointer.

Now if you had done this:
class CEffect{    CEffect( char* filename ) { m_fx = NULL ; D3DXCreateEffectFromFile( filename, m_fx, .....etc); }    ~CEffect() { SAFE_RELEASE( m_fx ); }    ID3DXEffect* m_fx;public:        ID3DXEffect* operator->() { return m_fx; }//..... other functionality}//An actual instance, not a pointerCEffect m_effect("fire.fx");m_effect->SetMatrix("World", worldMatrix);
then that last part should work. Do you see the difference? The operator must apply to an actual instance, not to a raw pointer to an instance.
"We should have a great fewer disputes in the world if words were taken for what they are, the signs of our ideas nly, and not for things themselves." - John Locke o
Omid Ghavami
Omid Ghavami
I just did a quick test:

class MyClass{public:	int myInt;};class TestClass{public:	TestClass(void);	~TestClass(void);	void setInt(int newInt)	{		myObject.myInt = newInt;		};	MyClass* TestClass::operator->( void )	{		return (&myObject);	};private:	MyClass myObject;};


TestClass tc;tc.setInt(20);std::cout << tc->myInt;


Compiles and prints out 20 as expected.

EDIT: Agony most likely hit the nail on it's head.
Best regards, Omid
sipickles
sipickles
Of course they are. I'd forgotten that.

Unfortunately, ID3DXEffect is an abstract class. It has to be a pointer :(

Guess I'll have to go back to my old way!
Agony
Agony
Does CEffect inherit from ID3DXEffect? Or is CEffect just a wrapper around an ID3DXEffect pointer? If it is the latter, then all you need is an instance of CEffect. It doesn't matter that your wrapped effect is a pointer. -> returns a pointer anyway, so that's fine.
"We should have a great fewer disputes in the world if words were taken for what they are, the signs of our ideas nly, and not for things themselves." - John Locke o
Omid Ghavami
Omid Ghavami
Quote:
Original post by sipickles
Of course they are. I'd forgotten that.

Unfortunately, ID3DXEffect is an abstract class. It has to be a pointer :(

Guess I'll have to go back to my old way!


As Agony pointed out it's the object of type CEffect which mustn't be a pointer, since if it's a pointer then the -> operator would that of a pointer and not that of an object of type CEffect. The returned value of the operator -> should be a pointer, which it is, so you don't have a problem there.
Best regards, Omid
Zakwayda
Zakwayda
I only skimmed the thread, so this may be completely irrelevant, but...

If the only purpose of the wrapper is to provide support for RAII, you might consider instead using boost::shared_ptr along with a custom deleter. You would then get operator->() (along with a number of other useful features and behaviors) essentially for free.
sipickles
sipickles
Its the latter, a wrapper. Unfortunately, the CEffect class is used by my CResourceManager< CEffect > class, which relies on pointers and memory allocation.

Wouldn't changing this to inherit from ID3DXEffect solve this?

---

edit: jyk may have a point. The custom deleter performs the release, right?
Zakwayda
Zakwayda
Quote:
Original post by sipickles
Its the latter, a wrapper. Unfortunately, the CEffect class is used by my CResourceManager< CEffect > class, which relies on pointers and memory allocation.

Wouldn't changing this to inherit from ID3DXEffect solve this?

---

edit: jyk may have a point. The custom deleter performs the release, right?
Here's another not-terribly-well-thought-out and perhaps-not-completely-relevant reply :)

To me it looks like you're not trying to abstract away any functionality here (that is, the fact that this is a DX-based framework is in no way kept from the user). Therefore it seems it would make more sense to simply manage objects derived from ID3DXEffect directly via smart pointers rather than using a wrapper.

In other words, I can think of two reasons you would want to wrap ID3DXEffect:

1. To support RAII
2. To abstract away its functionality

You're not doing '2', and '1' is already covered by boost::shared_ptr, so the custom wrapper seems somewhat superfluous.

I realize your resource manager class would require some reconfiguring to make it work with smart pointers, but I think this change would be worth considering.

Also, I should mention that I'm not that familiar with this part of the DX API, so I'm just assuming here that there are no technical problems with using shared_ptr in this context.

[Oop, didn't see your edit. Yes, with an appropriate custom deleter, shared_ptr will take care of freeing the resource for you (in true RAII fashion).]
sipickles
sipickles
Yeah the updating of my resource manager class to use boost::smart_ptr is top of my to do list!

Thanks for the advice!

Si
Emmanuel Deloget
Emmanuel Deloget
Quote:
Original post by rip-off
m_effect is a pointer, so you need to dereference the pointer to call CEffect::operator->(), which you overloaded:

(*m_effect)->...


It seems that someone missed that post. So I quote it again, as it contains all the needed information to understand why the current code is not working.

Topic Locked

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

Sign in to reply to this topic.