Interface Programming the basics

L

Lamefif

// C3DRect supports IDraw and IShapeEdit.
class C3DRect : public IDraw, public IShapeEdit
{
public:
C3DRect();
virtual ~C3DRect();
// IDraw
virtual void Draw();
// IShapeEdit
virtual void Fill (FILLTYPE fType);
virtual void Inverse();
virtual void Stretch(int factor);
};

//-----------------------------------

// Here is the global 3D rect.
C3DRect* ptheRect;

// Functions to operate on the 3D rect.
void CreateThe3DRect();
void DestroyThe3DRect();

Implementing CreateThe3DRect() and DestroyThe3DRect() is trivial.
Simply use the new and delete keywords to create and destroy the
object:

// Creation function.
void CreateThe3DRect()
{
// Create a 3d-rect.
ptheRect = new C3DRect();
}
// Destroy the rectangle.
void DestroyThe3DRect()
{
// See ya!
delete ptheRect;


//--------------------


// This method returns interfaces to the client.
bool GetInterfaceFrom3DRect(INTERFACEID iid, void** iFacePtr)
{
if(ptheRect == NULL){
cout << "You forgot to create the 3DRect!" << endl;
return false;
}
if(iid == IDRAW){ // They want access to IDraw.
// Cast the client's pointer to the IDraw interface of
ptheRect.
*iFacePtr = (IDraw*) ptheRect;
return true;
}
if(iid == ISHAPEEDIT) { // They want access to IShapeEdit.
// Cast the client's pointer to the IShapeEdit interface of
ptheRect.
*iFacePtr = (IShapeEdit*) ptheRect;
return true;
}
// I have no clue what they want.
*iFacePtr = NULL; // Just to be safe.
cout << "C3DRect does not support interface ID: " << iid <<
endl<< endl;
return false;
}
//----------------------------------------------------
int main()
{
bool retVal = false;
IDraw* pDraw = NULL;
//IDraw3* pDraw3 = NULL;
IShapeEdit* pShapeEdit = NULL;

CreateThe3DRect();

// Can I get the IDraw interface from object?
retVal = GetInterfaceFrom3DRect(IDRAW, (void**)&pDraw);
if(retVal)
pDraw->Draw();
DestroyThe3DRect();

return 0;
}
//-----



help me understand this please.
are we simply casting pointers from one type to the next here?
when selecting the interface with GetInterfaceFrom3DRect ,i have
iFacePtr which is a void pointer and ptheRect.

*iFacePtr = (IDraw*) ptheRect; <-- i dont get this part.
here iFacePtr is of IDraw type.. now we have ptheRect which is of
C3DRect, taking that casting it to IDraw and assigning it to iFacePtr.

does this mean we are working with an instance of C3DRect but of type
IDraw?
how did we managed that?
doesn't this mean we can make an instance of an abstract class by type
casting it?
As you can see im confused any easy to digest explanation would be
great.

thank you
 
?

=?ISO-8859-1?Q?Erik_Wikstr=F6m?=

// C3DRect supports IDraw and IShapeEdit.
class C3DRect : public IDraw, public IShapeEdit
{
public:
C3DRect();
virtual ~C3DRect();
// IDraw
virtual void Draw();
// IShapeEdit
virtual void Fill (FILLTYPE fType);
virtual void Inverse();
virtual void Stretch(int factor);
};

//-----------------------------------

// Here is the global 3D rect.
C3DRect* ptheRect;

// Functions to operate on the 3D rect.
void CreateThe3DRect();
void DestroyThe3DRect();

Implementing CreateThe3DRect() and DestroyThe3DRect() is trivial.
Simply use the new and delete keywords to create and destroy the
object:

// Creation function.
void CreateThe3DRect()
{
// Create a 3d-rect.
ptheRect = new C3DRect();
}
// Destroy the rectangle.
void DestroyThe3DRect()
{
// See ya!
delete ptheRect;


//--------------------


// This method returns interfaces to the client.
bool GetInterfaceFrom3DRect(INTERFACEID iid, void** iFacePtr)
{
if(ptheRect == NULL){
cout << "You forgot to create the 3DRect!" << endl;
return false;
}
if(iid == IDRAW){ // They want access to IDraw.
// Cast the client's pointer to the IDraw interface of
ptheRect.
*iFacePtr = (IDraw*) ptheRect;
return true;
}
if(iid == ISHAPEEDIT) { // They want access to IShapeEdit.
// Cast the client's pointer to the IShapeEdit interface of
ptheRect.
*iFacePtr = (IShapeEdit*) ptheRect;
return true;
}
// I have no clue what they want.
*iFacePtr = NULL; // Just to be safe.
cout << "C3DRect does not support interface ID: " << iid <<
endl<< endl;
return false;
}

Really stupid function, could be implemented much easier and cleaner
with something like this:

IDraw* getIDraw() {
return dynamic_cast<IDraw*>(ptheRect);
}

IShapeEdit* getIShapeEdit() {
return dynamic_cast<IShapeEdit*>(ptheRect);
}

And let the user check if the returned pointer is NULL.
//----------------------------------------------------
int main()
{
bool retVal = false;
IDraw* pDraw = NULL;
//IDraw3* pDraw3 = NULL;
IShapeEdit* pShapeEdit = NULL;

CreateThe3DRect();

// Can I get the IDraw interface from object?
retVal = GetInterfaceFrom3DRect(IDRAW, (void**)&pDraw);
if(retVal)
pDraw->Draw();
DestroyThe3DRect();

return 0;
}
//-----



help me understand this please.
are we simply casting pointers from one type to the next here?
Yes.

when selecting the interface with GetInterfaceFrom3DRect ,i have
iFacePtr which is a void pointer and ptheRect.

*iFacePtr = (IDraw*) ptheRect; <-- i dont get this part.

Cast the pointer ptheRect to a pointer to an IDraw object. Except that
it is assigned to a pointer to void, so you end up with a void pointer.
here iFacePtr is of IDraw type.. now we have ptheRect which is of
C3DRect, taking that casting it to IDraw and assigning it to iFacePtr.

does this mean we are working with an instance of C3DRect but of type
IDraw?

Nope, just pointers.
how did we managed that?
doesn't this mean we can make an instance of an abstract class by type
casting it?

No, we can have pointers (ore references) to objects of an abstract
class, but you can never instantiate an abstract class. That's how
abstract classes can work as interfaces.
 
L

Lamefif

Really stupid function, could be implemented much easier and cleaner
with something like this:

IDraw* getIDraw() {
return dynamic_cast<IDraw*>(ptheRect);

}

IShapeEdit* getIShapeEdit() {
return dynamic_cast<IShapeEdit*>(ptheRect);

}

And let the user check if the returned pointer is NULL.







Cast the pointer ptheRect to a pointer to an IDraw object. Except that
it is assigned to a pointer to void, so you end up with a void pointer.



Nope, just pointers.


No, we can have pointers (ore references) to objects of an abstract
class, but you can never instantiate an abstract class. That's how
abstract classes can work as interfaces.

So where is pDraw pointing to, IDraw?
the draw() method of IDraw does not have a body, i mean we are getting
the functionality of the Draw method we have written in C3DRect().

and we are creating one instance of C3DRect with CreateThe3DRect().

a good book suggestion on the subject or article would be appreciated
thanks
 
?

=?ISO-8859-1?Q?Erik_Wikstr=F6m?=

So where is pDraw pointing to, IDraw?

pDraw points to the C3DRect instance, same as ptheRect points to.
the draw() method of IDraw does not have a body, i mean we are getting
the functionality of the Draw method we have written in C3DRect().

Yes, since pDraw points to the C3DRect instance.
and we are creating one instance of C3DRect with CreateThe3DRect().

a good book suggestion on the subject or article would be appreciated
thanks

Any book describing polymorphic behaviour should do. The theory is the
same regardless which language you use. One way to look at it is that
the two pointers (ptheRect and pDraw) are two different interpretations
of the data they point to. ptheRect says that it points to a C3DRect
while pDraw claims to point to a IDraw. We both know that they both
point to a C3DRect, but since it behaves just like a IDraw we can also
treat it like one.
 
L

Lamefif

pDraw points to the C3DRect instance, same as ptheRect points to.


Yes, since pDraw points to the C3DRect instance.



Any book describing polymorphic behaviour should do. The theory is the
same regardless which language you use. One way to look at it is that
the two pointers (ptheRect and pDraw) are two different interpretations
of the data they point to. ptheRect says that it points to a C3DRect
while pDraw claims to point to a IDraw. We both know that they both
point to a C3DRect, but since it behaves just like a IDraw we can also
treat it like one.

ok i think i need just a little more pushing in the right direction.

pDraw and ptheRect both point to the same instance.
But treat it differently because they are declared to be of different
type to begin with?

i mean if pDraw points to C3DRect why aren't we seeing the rest of the
methods but only draw(), why are they hidden?

thanks for your replies, i appreciated :)
 
?

=?ISO-8859-1?Q?Erik_Wikstr=F6m?=

ok i think i need just a little more pushing in the right direction.

pDraw and ptheRect both point to the same instance.
But treat it differently because they are declared to be of different
type to begin with?
Yes.

i mean if pDraw points to C3DRect why aren't we seeing the rest of the
methods but only draw(), why are they hidden?

Because compilers are stupid and trust the programmer. This means that
when we access the data pointed to by ptheRect it will interpret the
data as a C3DRect, and when accessing it through pDraw it will interpret
it as an IDraw.

This is important when IDraw is not an abstract class, since if you then
make a copy of what pDraw points to, only the IDraw portion will be
copied and the rest ignored. This is called slicing and is usually not
what you want.
 
L

Lamefif

Because compilers are stupid and trust the programmer. This means that
when we access the data pointed to by ptheRect it will interpret the
data as a C3DRect, and when accessing it through pDraw it will interpret
it as an IDraw.

This is important when IDraw is not an abstract class, since if you then
make a copy of what pDraw points to, only the IDraw portion will be
copied and the rest ignored. This is called slicing and is usually not
what you want.

thanks to you im a lot less confused :)

you said earlier that GetInterfaceFrom3DRect is stupid, and should be
replaces with something like:
IDraw* getIDraw() {
return dynamic_cast<IDraw*>(ptheRect);

}


getIDraw being a method of C3DRect?

this seems to eliminate the need for interface ID's, if is not too
much to ask what other changes would you make.
i like to see how would you go about designing this, it dont matter if
the code is complex or rather i prefer it :)

and how would you go about implementing this in the main method,
something like?

IDraw* pDraw = NULL;

CreateThe3DRect();

pDraw = ptheRect->getIDraw();
..
..

DestroyThe3DRect();


Thanks again
 
?

=?ISO-8859-1?Q?Erik_Wikstr=F6m?=

thanks to you im a lot less confused :)

you said earlier that GetInterfaceFrom3DRect is stupid, and should be
replaces with something like:
IDraw* getIDraw() {
return dynamic_cast<IDraw*>(ptheRect);

}


getIDraw being a method of C3DRect?

this seems to eliminate the need for interface ID's, if is not too
much to ask what other changes would you make.
i like to see how would you go about designing this, it dont matter if
the code is complex or rather i prefer it :)

and how would you go about implementing this in the main method,
something like?

I'd get rid of the global variable, CreateThe3DRect, DestroyThe3DRect,
and GetInterfaceFrom3DRect. They don't serve any purpose that I can see.
IDraw* pDraw = NULL;

CreateThe3DRect();

pDraw = ptheRect->getIDraw();

We don't need a IDraw pointer to call Draw, we can do that from a
C3DRect pointer as well. In fact we don't need any pointers at all since
none of the code makes use of any polymorphic behaviour.


Since I don't know what the code is supposed to do I'd reduce it to the
minimum which should reproduce the same results:

//-----------------------------------

enum FillType { Solid, Dots, Stripes };

class IDraw
{
public:
virtual void Draw() = 0;
};

class IShapeEdit
{
public:
virtual void Fill (FillType fType) = 0;
virtual void Inverse() = 0;
virtual void Stretch(int factor) = 0;
};

//-----------------------------------

class C3DRect : public IDraw, public IShapeEdit
{
public:
C3DRect();
virtual ~C3DRect();
// IDraw
virtual void Draw();
// IShapeEdit
virtual void Fill (FillType fType);
virtual void Inverse();
virtual void Stretch(int factor);
};

//-----------------------------------

int main()
{
C3DRect rect;
rect.Draw();
return 0;
}

Notice the "= 0" at end of the function declarations in the interfaces,
this means that the functions are pure virtual and requires the user to
provide an overload in all classes inheriting from it. I use it to
indicate that those classes are pure interfaces with no implementation.
 
L

Lamefif

I'd get rid of the global variable, CreateThe3DRect, DestroyThe3DRect,
and GetInterfaceFrom3DRect. They don't serve any purpose that I can see.


We don't need a IDraw pointer to call Draw, we can do that from a
C3DRect pointer as well. In fact we don't need any pointers at all since
none of the code makes use of any polymorphic behaviour.

Since I don't know what the code is supposed to do I'd reduce it to the
minimum which should reproduce the same results:

//-----------------------------------

enum FillType { Solid, Dots, Stripes };

class IDraw
{
public:
virtual void Draw() = 0;

};

class IShapeEdit
{
public:
virtual void Fill (FillType fType) = 0;
virtual void Inverse() = 0;
virtual void Stretch(int factor) = 0;

};

//-----------------------------------

class C3DRect : public IDraw, public IShapeEdit
{
public:
C3DRect();
virtual ~C3DRect();
// IDraw
virtual void Draw();
// IShapeEdit
virtual void Fill (FillType fType);
virtual void Inverse();
virtual void Stretch(int factor);

};

//-----------------------------------

int main()
{
C3DRect rect;
rect.Draw();
return 0;

}

Notice the "= 0" at end of the function declarations in the interfaces,
this means that the functions are pure virtual and requires the user to
provide an overload in all classes inheriting from it. I use it to
indicate that those classes are pure interfaces with no implementation.

Thank you, been of great help. The book im reading "Developer's
Workshop to COM and ATL 3.0", its aim is towards COM programming. This
part was brush up on Interfaces.

Maybe this unnecessary complexity is needed later.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,053
Latest member
BrodieSola

Latest Threads

Top