Google Answers Logo
View Question
 
Q: Overloading Virtual Functions ( No Answer,   7 Comments )
Question  
Subject: Overloading Virtual Functions
Category: Computers > Programming
Asked by: fritzfinn-ga
List Price: $2.00
Posted: 26 Jul 2004 11:55 PDT
Expires: 25 Aug 2004 11:55 PDT
Question ID: 379269
Why can't Virtual Functions be overloaded?  What is the correct way to
construct a class when a case arises that seems to lend itself to
overloading Virtual Functions?  Is there an example of this
behavior in Design Patterns book by Erich Gamma?
Answer  
There is no answer at this time.

Comments  
Subject: Re: Overloading Virtual Functions
From: mikejv-ga on 26 Jul 2004 14:05 PDT
 
For C++: Do you read comp.lang.c++.moderated? Perhaps this will help:

http://tinyurl.com/4ad3z
Subject: Re: Overloading Virtual Functions
From: fritzfinn-ga on 27 Jul 2004 11:37 PDT
 
Not too much.  I'm not big on using e-mail or online forums for
assistance on complex issues.  I'd rather hire a consultant, get on
the phone, and cut to the chase.  In fact I tried to hire Scott
Meyers, who wrote Effective C++, and he sent me to the same place. 
Then I tried the guy who wrote C++ FAQ and his fees were unreasonable
at $400 per hour.

Anyhow, I did try, but just don't like it, at all.  It's a waste of
time.  On a simple questions yes, but I don't have time to monitor
this thing all the time and go back and forth, and back and forth.  I
wear about 10 different hats.  I need verbal information, pronto.

My posting this question on Google is basically an experiment.  I want
to see just how good a responses I can get.

I hope my response was not offensive.  Thanks for your suggestion.
Subject: Re: Overloading Virtual Functions
From: fritzfinn-ga on 27 Jul 2004 11:46 PDT
 
Actually, I didn't see the link you provided before I posted last
response.  Let me take a look and I'll get back to you.

Thanks
Subject: Re: Overloading Virtual Functions
From: nsinr8r-ga on 31 Jul 2004 08:50 PDT
 
You *can* overload virtual functions, but it's not a recommended
practice.  I tried it out with both GCC and MSVC++ 2003, and neither
gave me an error or warning (except for the warning I'll show after
the code below).

The best sources to read for why this is a bad idea (and what to do
instead) both come from the same author: Stephen Dewhurst.  Check out
his book, C++ Gotchas, which the code I show essentially comes from). 
The other is his website www.semantics.org, specifically his paper
http://www.semantics.org/talknotes/SD2002W_HIERARCHY.pdf, starting on
page 10.  I gotta say I learned a lot from that book.

The code in the book is simpler; I threw in a little more.  First
suppose you have two classes, Base and Derived, defined as:

#include <iostream>
using std::cout;

class Base {
  public:
    virtual void foo(int f) {
        cout << f;
    }
    virtual void foo(double f) {
        cout << f;
    }
};

class Derived : public Base {
  public:
    void foo(int f) {
        cout << f;
    }
};

int main() {

    Derived *d = new Derived;
    Base *b = d;

    cout << "Calling Base foo(double) through Base\n";
    b->foo(3.14);

    cout << "Calling Base foo(double) through Derived\n";
    d->foo(3.14);

    delete b;
}

The interesting thing here is that in the second case, when we're
trying to call the double version of foo() from the Derived instance,
we actually get the int version of foo().  What happened? 
Essentially, the override of foo() in Derived hid all of the
overloaded foo() functions in Base.

Dewhurst mentions two solutions in the book:
1) You could make sure that you have overloaded versions of the
virtual functions in all your derived classes.  This is pretty
inflexible, because anyone deriving from any of your classes will have
to know about all of the different overloaded versions and write
overloaded versions in their derived classes.  If they aren't aware of
them (and are only aware that foo() exists, they'll run into the same
problem: hidden member functions.
2) As he offers in the PDF, you can overload some non-virtual member
functions in the base class, then have a set of virtual functions
(with different names--not overloaded) that the overloaded non-virtual
functions call.  The following comes from his PDF (I called the
functions foo() to match the code above):

class Base {
  public:
    void foo(double);   // overloaded, non-virtual
    void foo(int);      // 
  protected:
    virtual void f_double(double);  // virtual, not overloaded
    virtual void f_int(int);        //
};
inline void foo(int i)    { f_int(i);    }
inline void foo(double d) { f_double(d); }

Maybe a little hairier conceptually, but definitely safer.  Check out both sources!

------M
Subject: Re: Overloading Virtual Functions
From: nsinr8r-ga on 31 Jul 2004 08:53 PDT
 
Sorry; I forgot to mention that the only warning I got (at least from
MSVC++) was that there would be a conversion from double to int, and
that there would be "a possible loss of data," which there was.  I had
requested 3.14 be printed to the screen, but it instead truncated the
number to an integer before printing.
Subject: Re: Overloading Virtual Functions
From: fritzfinn-ga on 01 Aug 2004 13:57 PDT
 
Thanks very much for responding.

Let me provide a better example.

Here are the classes:

CPortfolioBase which is abstract, i.e. it's never initialized alone.
So, the implimentation is done in each derived class.

CPortfolioCommodities derived from Base
CPortfolioStocks derived from Base

Let's say I have a function GetMarketWeight which retrieves a number
that weights a markets contribution to total profit.

For various reasons, in Commodity portfolio you need to know whether
your long or short, plus an index representing day. So, two arguments.

In Stock portfolio you only need to pass in day, not Long or Short. 
So, in each case I'd like to call "GetMarketWeight" from the Base
class, Commodity ::GetMarketWeight(LongOrShort, DayIndex) and
Stock::GetMarketWeight(DayIndex), but because you can't overload, you
have to setup both with two args.

So this is what I'd like to do:

class CPortfolioBase
{
 public:
  
  virtual float GetMarketWeight(short x, long y) = 0;
  virtual float GetMarketWeight(long y) = 0;
};

class CPortfolioCommodities : public CPortfolioBase
{
 public:
  float GetMarketWeight(short x, long y);
}

class CPortfolioStocks : public CPortfolioBase
{
 public:
  float GetMarketWeight(long y);
}


main()
{
  CPortfolioBase *b;
  CPortfolioCommodities c;
  CPortfolioStocks s;
  float x;
  
  x = c.GetMarketWeight(1,1500);
  x = s.GetMarketWeight(1500);
  
  b = &c;
  
  x = b->GetMarketWeight(1,1500);
  
  b = &s;
  x = b->GetMarketWeight(1500);

}


So, regarding both mikejv-ga and nsinr8r-ga suggestions:

My problem relates to overloading a pure virtual function.  Not overriding.
I briefly looked at C++ Gotchas.  But don't have the book.  I'll order it.

This is the problem I run into fairly often. There must be a "correct"
solution according to the C++ community for this issue.  Hopefully,
this is a more concrete example of my problem.

Thanks again.
Subject: Re: Overloading Virtual Functions
From: tractorguy-ga on 13 Aug 2004 12:55 PDT
 
#1: C++ requires an implementation of every pure virtual signature, so
that is why your code won't compile.  That's just the way C++ is.  The
interesting question is why?

Bland answer: Technically, every function signature needs to have a
function associated with it.  Your two base classes are each missing
one.  Result: compile error on any instantiation of a subclass.

More interesting is the case where the virtual functions are defined
in the base class (which is what to do about it).  C++ relates
functions with the same names and different numbers of arguments
primarily to support the presence of default values for those
arguments.  Consider the following code:

#include <iostream.h>


class V {
public:
  virtual int X(int a) {throw "Error in declaration of X(int) -
subclass does not define method";}
  virtual int X(int a, int b) {throw "Error in use of X(int,int) -
subclass does not define method";}
  V() {}
  virtual ~V() {}
};

class W : public V {
public:
  int X(int a) {return a+1;}
  W() {}
  ~W() {}
};

class Z : public V {
public:
  int X(int a, int b=-1) {return -9;}
  Z() {}
  ~Z() {}
};



int main( int, char** ) {
  Z z;
  V& v=(V&)z;
  try {
    cerr << z.X(1,2) << endl;
    cerr << z.X(1) << endl;
    cerr << v.X(1,2) << endl;
    cerr << v.X(1) << endl;
  } catch ( const char* estr ) {
    cerr << "Exception:: " << estr << endl;
  }
}


It compiles and outputs :

-9
-9
-9
Exception:: Error in declaration of X(int) - subclass does not define method

Without the default value in the declaration of X in class Z, we get a
compile error (method not defined for z.X(1)).

So, I believe this was an attempt by C++ designers to somewhat support
default values and the autocasting of argument types at compile time
in the least confusing way.  C++ made the (reasonable) decision that
if a function call was ambiguous, it was a compile error.  But with
default values for some of a function's arguments, many functions
could become ambiguous in the presence of inheritance if all ancestor
methods are available as candidate instantiations.  This would make
default values unusable.  So the designers simply said "if a subclass
is going to define a method, it will have to define *all methods that
will be used by variables of its type*".  This is reasonable, since it
would in any case be confusing if you define a function in a subclass
and end up with a parent's instantiation in use due to some weird
unforseen autocasting and default value filling.

Note that in my code above, it compiles and allows you to use Z.X(a,b)
and W.X(a) without defining Z.X(a) or W.X(a,b) *provided you don't
refer to W.X(a,b) or Z.X(a) in your code*.

That's my $0.02.

Important Disclaimer: Answers and comments provided on Google Answers are general information, and are not intended to substitute for informed professional medical, psychiatric, psychological, tax, legal, investment, accounting, or other professional advice. Google does not endorse, and expressly disclaims liability for any product, manufacturer, distributor, service or service provider mentioned or any opinion expressed in answers or comments. Please read carefully the Google Answers Terms of Service.

If you feel that you have found inappropriate content, please let us know by emailing us at answers-support@google.com with the question ID listed above. Thank you.
Search Google Answers for
Google Answers  


Google Home - Answers FAQ - Terms of Service - Privacy Policy