Jump to content
  • Advertisement
Sign in to follow this  
Harry Hunt

References and implicit casts

This topic is 4005 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi! I have a class Foo and a bunch of other classes just like Foo that implement an interface IBar like so:
class IBar
{
public:
  virtual void DoBar() = 0;
};

class Foo : public IBar
{
public:
  void DoBar
  {
    ...
  }
};
I also have another interface IFooBar
class IFooBar
{
public:
  virtual IBar GetBar() = 0;
};
and a couple of classes that implement IFooBar. However, I want each of these classes to return their own implementation of IBar in their GetBar-method:
IBar MyFooBar::GetBar()
{
  return Foo();
}
Now I'm not sure if that's even legal (I doubt it), but it gets worse:
MyFooBar y;
IBar& x = y.GetBar();
This gives me the following error "IBar: cannot instantiate abstract class". So what's my best bet here? When I return by reference it seems to work, but I'm not sure if that's the best and/or nicest way of doing it. Since the GetBar method returns a new object, returning by reference doesn't seem like a good idea. However, I also don't want to sacrifice my interfaces... Thanks a lot in advance!

Share this post


Link to post
Share on other sites
Advertisement
To return objects of different types, you need to return a reference or a pointer. Seeing as you wish to return a new object, you cannot return a reference. So, make GetBar return an IBar pointer or a smart IBar pointer, such as std::auto_ptr<IBar> or boost::shared_ptr<IBar>.

Share this post


Link to post
Share on other sites
Since the problem's resolved and we're on the topic of implicit casts and references, perhaps somebody could fill a gap in my C++ knowledge.

Many people use the SAFE_RELEASE macro to release COM objects without having to worry about dereferencing a null pointer. Like many, I object exclusively to the use of macros, but I came a-cropper when trying to implement an equivalent function:
void SafeRelease(IUnknown* pRes) {
if (pRes != NULL) pRes->Release();
}
This works just fine, but ideally I'd have the pointer nullified after releasing its object. So as not to have to change client code, I figured a reference-to-pointer would be the solution, but the compiler complains about implicit casting-to-reference when I try this:
void SafeRelease(IUnknown*& pRes) {
if (pRes != NULL) pRes->Release();
pRes = NULL;
}
Is there any hope for my plight?

Admiral

Share this post


Link to post
Share on other sites
Quote:

the compiler complains about implicit casting-to-reference when I try this


What error message do you get? Can you post a minimal example which generates this error?

Share this post


Link to post
Share on other sites
Quote:
Original post by rip-off
What error message do you get? Can you post a minimal example which generates this error?
Sorry - I should have bothered to try to compile this before posting. The situation isn't as simple as I made out. Everything compiles fine when I pass it a IUnknown*, but the problem is that it doesn't (or I don't) know how to down-cast a pointer to a derived class appropriately:


void SafeRelease(IUnknown*& pRes) {
if (pRes != NULL) pRes->Release();
pRes = NULL;
}

class Derived : public IUnknown {};

void ProblemFunction() {
Derived* instance; // Let's pretend this has been initialised
SafeRelease(instance);
}


This gives a compile error:

error C2664: 'SafeRelease' : cannot convert parameter 1 from 'Derived *' to 'IUnknown *&'

I suspect this could be solved by casting inside the call to SafeRelease, but I'd really rather not clutter up the client code.

Admiral

Share this post


Link to post
Share on other sites
The first thing that comes to mind would be to make a template function:

template< class Derived >
void SafeRelease( Derived *& pointer )
{
IUnknown *unknown = pointer;
if( unknown )
{
unknown->Release();
}
pointer = 0;
}



I think I can see how this could cause an error. Consider if the following example were to compile:

struct IUnknown
{
virtual void Release() = 0;
};

struct Concrete : IUnknown
{
virtual void Release(){}
};

struct Bad : IUnknown
{
virtual void Release(){}
};

void bad( IUnknown *& unknown )
{
unknown = new Bad;
}

int main()
{
Concrete *concrete = new Concrete;
bad(concrete);
// Concrete pointer points to unrelated class!
}

Share this post


Link to post
Share on other sites
Okay, I see the problem now.

Unfortunately, DirectX offers a cornucopia of IUnknown-derived interfaces and it seems devious to specialise a template for each one I use. I think I'll just stick to clearing the pointer in client code.

Nevertheless, it's reassuring to know that haven't just missed something obvious.

Thanks for the help
Admiral

Share this post


Link to post
Share on other sites
http://www.parashift.com/c++-faq-lite/proper-inheritance.html#faq-21.2

Passing a reference to a pointer is the same as passing in a pointer to a pointer in this case, except the semantics are different.

The same problem exists; because the IUnknown pointer is modifyable, you could make it point to something completely random that's derived from IUnknown.

For example, if your function was legal, I could do this:

void SafeRelease(IUnknown*& pRes) {
ID3DDevice9* D3DDevice;
// ...
pRes = D3DDevice;
}


And it would work fine. And what if I did this with your function:

IDirectInput8* Input;
// ...
SafeRelease(Input);



My IDirectInput8* would be made to point to an ID3DDevice9. Which would be very, very bad.

Share this post


Link to post
Share on other sites
Quote:
Original post by TheAdmiral
Unfortunately, DirectX offers a cornucopia of IUnknown-derived interfaces and it seems devious to specialise a template for each one I use. I think I'll just stick to clearing the pointer in client code.


Why not use the template? It will work for every IUnknown derived interfaces, without specialisation. You shouldn't have to specialise it. Try it out.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!