[comp.lang.c++] Functions not defined in base class

goss@ese.essex.ac.uk (Gossain Sanjiv (5N.7.10)) (05/04/89)

I have a particular application where I am representing a group
of related classes by an abstract class. Now, I require that
another object of another class, is passed an instance of
one of these classes as a parameter in one of its methods. 
I would like to be able to declare the abstract class as the 
type in the functiion declaration, as I won't know until
run time, which class of my group it will be. Are you
confused? Let me explain with some code...


I would like a function of class X ( X::A) to have the decl:

void X::A(abstractClass* aMemberOfAbsClass)

now, aMemberOfAbsClass could be any instance of a sub-class
of abstractClass.

X::A should be able to call a member function of aMemberOfAbsClass
that is not defined for abstractClass, should I

---OPTION 1 ----

(1) Define an empty function with the same name as for the sub-class
    in the base-class's declaration. 

e.g.
 
class Y {
   int a;
public:
    Y(int dd)   { a = dd; }
    virtual int get_both() { }
};

class Z : public Z {
   int y;
public:
    Z(int dd, int gg) : (dd) { y = gg; }
    int get_both()      { return y*Y::get(); }
};

and then use ...

main()
{
  ...
  ...
  Y* someZ = new Z(2,3);
  someX->A(someZ);
  ...
}

with get_both() being used in the body of X::A ...

void X::A(Y* someYorZ)
{
  //..
  someYorZ->get_both();
}

---------------

Or 

(2) should I do some sort of casting operation?


(I hope the question is clear)

Which is the better practice, or is there some other alternative.
Any help from C++ gurus gladly appreciated.


		-- Sanjiv

******************************************************************
Sanjiv Gossain          | goss%ese.essex.ac.uk@nsfnet-relay.ac.uk
Dept. of ESE            | Tel: +44 206 873333 Ext. 2820
University Of Essex                      
Colchester CO4 3SQ                       
ENGLAND                                  
******************************************************************

rfg@riunite.ACA.MCC.COM (Ron Guilmette) (05/04/89)

In article <897@servax0.ESSEX.AC.UK> goss@ese.essex.ac.uk writes:

    { and I paraphrase ... }

{Given that I have a pointer to an object, and given that the object is
itself (at least) of some particular base class, I would like to...}

>... be able to call a member function of {the actual derived class type of the object}
>that is not defined for {the obvious static base class type of the object}, should I
>
>---OPTION 1 ----
>
>(1) Define an empty function with the same name as for the sub-class
>    in the base-class's declaration. 
...
>Or 
>
>(2) should I do some sort of casting operation?

I would also like an answer to this question.  What is stylistically preferable?
Is there a consensus on which of these alternatives is better?

-- 
// Ron Guilmette  -  MCC  -  Experimental Systems Kit Project
// 3500 West Balcones Center Drive,  Austin, TX  78759  -  (512)338-3740
// ARPA: rfg@mcc.com
// UUCP: {rutgers,uunet,gatech,ames,pyramid}!cs.utexas.edu!pp!rfg

shopiro@alice.UUCP (Jonathan Shopiro) (05/04/89)

In article <897@servax0.ESSEX.AC.UK>, goss@ese.essex.ac.uk (Gossain Sanjiv (5N.7.10)) writes:
[slightly edited]
> I have a particular application where I am representing a group
> of related classes by an abstract class. Now, I require that
> a function is passed an instance of
> one of these classes as a parameter in one of its methods. 
> I would like to be able to declare the abstract class as the 
> type in the function declaration, as I won't know until
> run time, which class of my group it will be. Are you
> confused? Let me explain with some code...
> 
> I would like a function to have the decl:
> 
> void f(abstractClass* anInstanceOfAbsClass)
> 
> now, anInstanceOfAbsClass could be any instance of a sub-class
> of abstractClass.
> 
> f should be able to call a member function of anInstanceOfAbsClass
> that is not defined for abstractClass, should I
> 

There are (approximately) two cases:

1)  There is some function that will be implemented in every derived
class, but it has different implementations in each.

This is exactly what virtual functions were invented for.  Here's how:

class abstractClass {
	// ...
public:
	virtual void	function() = 0;   // a ``pure virtual'' function
};

The initializer is new syntax with 2.0.  It has several effects:
	1) you don't need an implementation for the base class
	2) you must redeclare it in each derived class (possibly
	    also as pure virtual)
	3) you can only create objects of the derived classes
If you call the function directly or indirectly in the constructor
of the base class, something bad will happen, but as soon as the
base class constructor completes, all will be well.

2)  There is some function that is only appropriate for some of
the derived classes.

This case is more problematical.  What you should look at is how you
might decide to call the function.  Perhaps the function is a sub-
operation of some function that is defined for all the derived
classes.  Then you can just put it in the classes where it is
appropriate.

	class Base {
		// ...
	public:
		virtual void	function() = 0;
	};
	class Derived : public Base {
	public:
		void	function();
		void	special();
	};
	void	Derived::function()
	{
		// ...
		special();
		// ...
	}

Here ``function'' will be defined in all derived classes, and
``special'' is not defined in all derived classes.  This is the most
natural way to use C++, and you should try to structure your programs
in this way.  I am sure you will like the result.

If this is not possible, you have two choices.  First, you can put the
special function in only the class where it is appropriate and then
use a cast to call it.  Using the declarations above, you could write

void f(Base* bp)
{
	// decide that bp really points to a Derived object, and you
	// want to call special
	((Derived*)bp)->special();
}

This is guaranteed to work only if bp really does point to a Derived
object.  If the special function will be defined in several derived
classes, but not all, you can create an intermediate class, derived
from Base, which has special as a pure virtual function, and then
derived the classes which will implement special from that.  There is
no performance penalty for extra classes in a derivation hierarchy.

The other choice is to put special in the Base class, as a virtual
function whose implementation calls some error routine, and to
override it in the appropriate derived classes.  The advantage of this
approach is that you get to define the behavior in case of error, and
the advantage of the other approach is that each class has only
appropriate member functions.  Personally I prefer the first approach,
with casting.
-- 
		Jonathan Shopiro
		AT&T Bell Laboratories, Warren, NJ  07060-0908
		research!shopiro   (201) 580-4229

johnson@p.cs.uiuc.edu (05/05/89)

Given the choice of
	1) defining a virtual function with a null body in the base class
and	2) casting a pointer
I would ALWAYS pick 1.  One of the characteristic features of an abstract
class is that it relies on code that is defined by subclasses.  Virtual
methods provide this mechanism in C++.  Abstract classes are one of the
key ideas in object-oriented design and the most important functions
in an abstract class are usually the ones that are defined in the
subclasses.  An abstract class essentially contains the instructions
for deriving subclasses from it, because you just define the functions
that are left to the subclasses.  C++ requires that virtual functions be 
defined in the base class, so you have to provide a dummy body or the 
loader will complain.

This idea is certainly not specific to C++, but is a feature of all
object-oriented languages.  In Smalltalk, the base of most large
class hierarchies is abstract, such as Collection, Number, and DisplayObject.
When it isn't, such as class View, it usually should be.

Ralph Johnson

lsr@Apple.COM (Larry Rosenstein) (05/06/89)

In article <897@servax0.ESSEX.AC.UK> goss@ese.essex.ac.uk (Gossain Sanjiv 
(5N.7.10)) writes:
> I have a particular application where I am representing a group
> of related classes by an abstract class. Now, I require that

A good thing to do, assuming you haven't already, is to make the 
constructor for the abstract class protected.  Then clients cannot create 
instances of the abstract classes, only of the concrete classes (which 
have public constructors).  

Larry Rosenstein, Apple Computer, Inc.
Object Specialist

Internet: lsr@Apple.com   UUCP: {nsc, sun}!apple!lsr
AppleLink: Rosenstein1

mat@mole-end.UUCP (Mark A Terribile) (05/06/89)

> I have a particular application where I am representing a group of
> related classes by an abstract class. Now, I require that another
> object of another class, is passed an instance of one of these
> classes as a parameter in one of its methods.  I would like to be
> able to declare the abstract class as the type in the function
> declaration, as I won't know until run time, which class of my group
> it will be. Are you confused? Let me explain with some code...

A little.  Isn't this what derived types are all about?  If you want other
classes to interpret instructions originally designed for one class, you
derive the other classes from it.

You are limited for a little while longer to single inheritance, so you
may have problems if you have something else you want for a base class.
When Multiple Inheritance comes along, this restriction will be lifted.

> I would like a function of class X ( X::A )

> void X::A( abstractClass* aMemberOfAbsClass )

> now, aMemberOfAbsClass could be any instance of a sub-class
> of abstractClass.

Eh?  I think you mean InstanceOfAbsClass ...

> X::A should be able to call a member function of aMemberOfAbsClass
> that is not defined for abstractClass, should I

> (1) Define an empty function with the same name as for the sub-class
>     in the base-class's declaration. 

Absolutely.  That's what virtual functions are for.  Provide yourself as
many empty virtual functions as you need in the base class.  This ensures
that any call is legal for any derived object.

> class Y {
>    int a;
> public:
>     Y(int dd)   { a = dd; }
>     virtual int get_both() { }
> };
> 
> class Z : public Z {
>    int y;
> public:
>     Z(int dd, int gg) : (dd) { y = gg; }
>     int get_both()      { return y*Y::get(); }
> };

I don't see a  get()  in the declaration of Y() .  If we assume it's there,
you only need the qualifier  Y::  if class Z declares a  get()  of its own.

> (2) should I do some sort of casting operation?

I hope you're not seriously thinking of this!  There's a mechanism provided
that doesn't violate the type structure.  Because of the way that pointers
to virtual functions are implemented, a really well botched miscast could do
all sorts of bad things.
-- 

(This man's opinions are his own.)
From mole-end				Mark Terribile