haskell@grant.cs.unc.edu (Phyllis Haskell) (01/13/88)
We're having a problem trying to use overloaded operators with derived classes. A sample program follows in which we are attempting to pass a derived class to the routine "test", which we want to multiply the instances of any derived class. We want "test" to be a generic routine which does not need to "worry" about the types of arguments used in its invocation. Is there a way to do this? #include <stdio.h> class Datatype { public: virtual Datatype* newobj() {fprintf (stderr,"newobj for base\n");} virtual void dump() { fprintf (stderr," dump undefined for base class\n");} }; class Dint: public Datatype { int temp; public: Dint () {} Dint (int in) {temp = in;} Dint& operator* (Dint& in) { Dint& newvar = *new Dint; newvar.temp = temp * in.temp; return newvar; } Datatype* newobj() {fprintf (stderr,"newobj for Dint\n"); return new Dint;} void dump () { fprintf (stderr, "Dint = %d\n", temp); } }; void test(Datatype& in, Datatype& in2) { Datatype* temp = in.newobj(); // create an instance of a subclass ?? /* (*temp) = in * in2; // here's our problem - how do we get proper // * operator for subclass. (commented to prevent // compiler error) */ temp->dump(); } main () { Dint inta(5), intb(6); test(inta, intb); }
weh@druhi.ATT.COM (HopkinsBWE) (01/14/88)
In article <656@thorin.cs.unc.edu>, haskell@grant.cs.unc.edu (Phyllis Haskell) writes: # # We're having a problem trying to use overloaded operators with derived classes. # A sample program follows in which we are attempting to pass a derived class to # the routine "test", which we want to multiply the instances of any derived # class. We want "test" to be a generic routine which does not need to "worry" # about the types of arguments used in its invocation. Is there a way to do this? # # # #include <stdio.h> # class Datatype # { # public: # virtual Datatype* newobj() {fprintf (stderr,"newobj for base\n");} # virtual void dump() { fprintf (stderr," dump undefined for base class\n");} virtual Datatype& operator * (Datatype& in) {} virtual int getTemp () {} virtual void operator = (Datatype&) {} # }; # # class Dint: public Datatype # { # int temp; # public: # Dint () {} # Dint (int in) {temp = in;} /***************************************************************************** # Dint& operator* (Dint& in) # { # Dint& newvar = *new Dint; # newvar.temp = temp * in.temp; # return newvar; # } ****************************************************************************/ Datatype& operator* (Datatype& in) { Dint& newvar = *new Dint; newvar.temp = temp * in.getTemp (); return newvar; } int getTemp () { return temp; } void operator = (Datatype& in) { temp = in.getTemp (); } # Datatype* newobj() {fprintf (stderr,"newobj for Dint\n"); # return new Dint;} # void dump () { fprintf (stderr, "Dint = %d\n", temp); } # }; # # void test(Datatype& in, Datatype& in2) # { # Datatype* temp = in.newobj(); // create an instance of a subclass ?? # (*temp) = in * in2; // here's our problem - how do we get proper # // * operator for subclass. (commented to prevent # // compiler error) # temp->dump(); # } # # main () # { # Dint inta(5), intb(6); # test(inta, intb); # } Compilation and execution: weh<top>CC net.c CC net.c: "net.c", line 10: warning: no value returned from Datatype::newobj() "net.c", line 10: warning: no value returned from Datatype::operator *() "net.c", line 10: warning: no value returned from Datatype::getTemp() cc net.c -lC weh<top>a.out newobj for Dint Dint = 30 The problem was that operator * was not declared for Datatype and the references to the Dint objects is via Datatype references. C++ requires that any operation invoked on an object via a some reference or pointer must be defined for the type of the reference or pointer. In other words, the type of the reference or pointer defines the set of operators than can be invoked (a.k.a. the ``signature''). Those operations whose implementations are to be provided by derived objects would be declared as virtual. This example, as you can tell from the changes that had to be made, presented a number of other complications, the reasons for which are left as an exercise for the reader. Bill Hopkins AT&T ihnp4!druhi!weh
jima@hplsla.HP.COM (jim adcock ) (01/14/88)
/* If I understand your test constraints correctly, this is as close as I can figure out to meeting your requirements. The general idea is that in each derived class Dxxxx, derived from Datatype, there would be two operator* methods: virtual Datatype& operator*(Datatype& in) and [non-virtual] Dxxxx& operator*(Dxxxx& in) where the second (non-virtual) method would provide a fast in-line method to be used between two objects of class Dxxxx for "real" programming usage, and the first method provides a "virtual" interface to the second method, to be called by the test routine. Unfortunately, allowing overloading of methods NOT defined in the base class does not seem to be implemented in the present AT&T compiler. (See what happens when you change operator_mpy to operator* in all places where operator_mpy is used -- the AT&T compiler says: "Sorry, we haven't implemented this feature !!!") So, my workaround was to come up with the "fake" name "operator_mpy" for the virtual version of the "operator*" function. *** SIGH *** It will be nice when we get a "finalized" C++ compiler !!! PS: The approach taken puts a "hidden" pointer to the virtual function dispatch table in each object. It's unclear from your question whether this would be acceptible overhead or not. If not, the only solution I would have is to put the virtual/test functions in each class inside an #ifdef TEST block, so that they would not be compiled in the final release of your software. (The pointer to the virtual dispatch table is placed in an object ONLY if it or its superclasses uses virtual functions) */ #include <stdio.h> class Datatype { public: Datatype() {}; virtual const char* isA() {return "Datatype";}; virtual void dump() { fprintf (stderr,"no value to dump in Datatype\n");}; virtual Datatype& /* operator* */ operator_mpy(Datatype& in) { fprintf(stderr,"Datatype operator* incorrectly used\n"); exit(1); return *this; }; }; class Dint: public Datatype { int temp; public: Dint () {}; Dint (int in) {temp = in;}; virtual const char* isA() { return "Dint";}; virtual Datatype& /* operator* */ operator_mpy(Datatype& in); Dint& operator* (Dint& in) { Dint& newvar = *(new Dint); newvar.temp = temp * in.temp; return newvar; } void dump () { fprintf (stderr, "Dint = %d\n", temp); } }; virtual Datatype& /* operator* */ Dint::operator_mpy(Datatype& in) { if (in.isA() != isA()) { fprintf(stderr,"mismatch in Dint operator*\n"); exit(1); } return (*this) * (*(Dint*)(&in)); } class Dflt: public Datatype { float temp; public: Dflt () {}; Dflt (int in) {temp = (float)in;}; virtual const char* isA() { return "Dflt";}; virtual Datatype& /* operator* */ operator_mpy(Datatype& in); Dflt& operator* (Dflt& in) { Dflt& newvar = *(new Dflt); newvar.temp = temp * in.temp; return newvar; } void dump () { fprintf (stderr, "Dflt = %f\n", temp); } }; virtual Datatype& /* operator* */Dflt::operator_mpy(Datatype& in) { if (in.isA() != isA()) { fprintf(stderr,"mismatch in Dflt operator*\n"); exit(1); } return (*this) * (*(Dflt*)(&in)); } void test(Datatype& in, Datatype& in2) { Datatype* temp = &(in.operator_mpy(in2)); temp->dump(); } main () { Dint inta(5), intb(6); Dflt flta(5), fltb(6); test(inta, intb); test(flta, fltb); }