Anthony,
See the few additions/modifications in your code below. You are very close
but only missing a few items. You need to use virtual member functions
rather than simple member functions. Which means you need to derive from an
base class that declares a virtual member function.
"Anthony Jones" <me@privacy.net > wrote in message
news:3K******** ************@ni ldram.net...
Just a bit of background: I'm one of a group of FORTRAN programmers,
looking to switch to C++. We are trying to write a few simple examples to
demonstrate the power of the language to our manager, so he will send us
all on a conversion course.
One of many reasons is that our code is littered with examples of:
SUBROUTINE PRINT_ITEM(ITEM , ITEM_TYPE)
IF (ITEM_TYPE .EQ. SQUARE) THEN
CALL PRINT_SQUARE(IT EM)
ELSEIF (ITEM_TYPE .EQ. CIRCLE) THEN
CALL PRINT_CIRCLE(IT EM)
ELSEIF ...
(lots more item types)
ENDIF
END
(with apologies for sullying the group with FORTRAN code).
Obviously We need to find and modify all these blocks whenever we add a
new object type, or operation.
I want to write a C++ equivalent, using classes and member functions so
that I can print (or draw, or interrogate, or whatever...) an object without
knowing its type at runtime.
The latest of several attempts is shown below - the compiler complains
about the void* in the PrintObject function, though I thought I'd read that
void* could be used to mean "pointer to something, but I don't know what".
Can this code be modifed to get the effect I want? I'd like to avoid using
pointers to functions if possible.
Thanks!
#include <iostream.h>
// Class declarations
// ------------------
class Geometry
{
public:
virtual ~Geometry(){} // need a virtual destructor in this case
virtual void Print(){}
};
class Square{
replace with:
class Square : public Geometry{
public:
void Print();
};
void Square::Print() {
cout << "This is a square";
}
class Circle{
replace with:
class Circle : public Geometry{
public:
void Print();
};
void Circle::Print() {
cout << "This is a circle";
}
// Print object function
// ---------------------
void PrintObject(voi d* object){
object->Print();
}
replace with:
void PrintObject( Geometry* aObjectPtr )
{
aObjectPtr->Print();
}
or better yet:
void PrintObject( Geometry& aObject ) // by reference
{
aObject.Print() ;
}
// Main Program
// ------------
int main(){
Square* square;
Circle* circle;
square = new Square;
circle = new Circle;
// Call member functions directly
circle->Print();
square->Print();
// Call member functions through PrintObject function
PrintObject(cir cle);
PrintObject(squ are);
to use the reference version replace with:
PrintObject( *circle ); // dereference the pointers to get references
PrintObject( *square );
return 0;
}
Better yet is to forego dealing with pointers altogether.
int main()
{
Square lSquare;
Circle lCircle;
lCircle.Print() ;
lSquare.Print() ;
PrintObject( lSquare );
PrintObject( lCircle );
return 0;
}
Additionally, since typically a Print function would not modify the state of
it's object, it's best to declare the member function as 'const'. As in:
class Geometry
{
public:
virtual ~Geometry(){}
virtual void Print()const{}
};
And finally to show the real power:
#include <vector>
int main()
{
typedef std::vector<Geo metry*> ;
tGeoPtrs lGeoPtrs;
lGeoPtrs.push_b ack( new Circle );
lGeoPtrs.push_b ack( new Square );
lGeoPtrs.push_b ack( new Circle );
lGeoPtrs.push_b ack( new Square );
lGeoPtrs.push_b ack( new Circle );
for( tGeoPtrs::itera tor lItr = lGeoPtrs.begin( ) ; lItr != lGeoPtrs.end()
; ++lItr )
{
(*lItr)->Print();
// or
PrintObject( *lItr ); // Pointer overload
// or
PrintObject( **lItr ); // reference overload
delete *lItr; // delete it when we're done
*lItr = NULL;
}
return 0;
}
This is just the beginning of the power/expressivenes advantages of C++
versus Fortran.
Jeff F