You are here:

C++/c/c++ Overloading problem

Advertisement


Question
Hi,


i  am stuck on a Alocated_variable_mem_stack class.
see source here: http://people.zeelandnet.nl/marco01974/cpp.zip


// example code (to explain what goes wrong)
template <class Ptype>
class Base
{
Ptype * m_data;

};

class Variant
{
Base<int> m_Pint; // = * var
Base<char> m_Pchar; // = * var

public;
void set(int x){} // works
void set(char * x}{} // works

// get (doesn`t work)

int get(){return *m_Pint.data;}
char * int get(){return *m_Pchar.data;}
---------^^^^^^^^^^^-------------
// error: function get already defined.. :=(

};

This is some psuedo code.. the source is more complex and has 1 error (function GET already defineD :-( )
download my src on http://people.zeelandnet.nl/marco01974/cpp.zip

if it would work, i could make all aplication variables resist on a class object ++ being dynamicly freed if they leave c++ scope.


if i can get GET FUNCTON overloaded it would be perfect for me.

Thanx.  

Answer
[note: I have not got the time to read through your full code so have only looked at what you posted in your question - sorry]

The reason you are having problems is that you cannot overload function names on return type in C++. Overloaded functions have to differ in either the number of parameters or the type of at least 1 parameter.

The reason (from "The C++ Programming language 3rd edition" by Bjarne Stroustrup section 7.4.1) is to keep the resolution of which overloaded function to call context independent (i.e. looking at just the call to a function is enough to determine which overload is called). He gives the following example:

   float sqrt( float );
   double sqrt( double );

   void fn( double da, float fa )
   {
       float f = sqrt( da );     // calls sqrt(double)
       double d = sqrt( da );    // calls sqrt(double)
       f = sqrt( fa );          // calls sqrt(float)
       d = sqrt( fa );          // calls sqrt(float)
   }

The comments show which overload of sqrt is called, and are easily worked out just by looking at the type of the argument passed to sqrt, and only the call to sqrt needs to be considered (sqrt(da) or sqrt(fa) in the example). If the return type were taken into account then much more of the expression needs to be taken into account in order to determine which overload to call, as what the return type of the function is needs to be determined (for example d = sqrt( fa )). Now the example has simple cases, how about these cases:

   d = sqrt( sqrt(fa) + sqrt(da) );
   f = sqrt( sqrt(da) + sqrt(fa) );

Then of course it is legal and common not to store the return value at all in C and C++, as below:

   sqrt( da );

In such cases overload resolution would be impossible if the return type needed to be taken into account as there is none (i.e. it could be void or anything else).

So I think that with all this extra complexity to allow overloading on return types peoples brains imploded and they said enough is enough - we will not allow it!

So what options do you have?

Well the most obvious is to give your get functions different names, maybe getInt, getChar, getCStr or some such.

Another, which in this case may be acceptable as you seem to be implementing some sort of variant type would be to provide type conversion operators for each type you variant can represent:

   operator int()  const { return *m_Pint.data; }
   operator char() const { return *m_Pchar.data; }

Note that I specify operator char not char* this is because your class stores pointers to int and char not pointers to int and char*.

You should also be aware of potential ambiguities where a value can be converted either by a call to a single parameter constructor or to a conversions operator and problems caused due to the sort of conversion usually applied implicitly for you, such as char to int conversions. Assigning a char variant to an int will probably cause the operator int to be called even if the variant contains a char. In such cases explicit conversion is required using a cast. For more on conversion operators see for example "The C++ Programming language 3rd edition" section 11.4.

You seem to be storing multiple pointers, is this really necessary?

In the past I have used a similar but simpler approach to this sort of problem. Again I defined a base type which acts as a common base class and defined an empty virtual destructor, the reason for which I describe below:

   // Header
   class VariantBase
   {
   public:
       virtual ~VariantBase();
   };

   // Implementation
   VariantBase::~VariantBase()
   {
   }

Unlike your base type however this is not a template type, and pointers to which can be stored in your stack or used in other places where you require a variant type. The variant type itself is a template, which can store a single value of any type T, and is derived from VariantBase:

   // Header
   template <class T>
   class Variant : public VariantBase
   {
   public:
       explicit Variant( T value ) // Note: value is passed by value
       : mValue( value )
       {
       }

       virtual ~Variant();

   // Variant<T> is convertible to T (T must be copyable)
       operator T()          {
         return mValue;
       }

   private:
       T   mValue; // Copy of value passed in constructor
   };

   // Header (assuming inclusion model for templates)
   template <class T>
   Variant<T>::~Variant()
   {
   }

You use these classes like so (assuming an STL like stack type):

   stack s<VariantBase*>;

   s.push( new Variant<int>(10) );
   s.push( new Variant<char>('x') );

To extract items safely I used dynamic_cast:

   Variant<char>* v = dynamic_cast<Variant<char> >( s.top() );
   if ( ! v )
   {
   // handle wrong element type error
   }
   char c = v;

These details can of course can be wrapped up and made generic in a template function.

The reason for VariantBase having a virtual destructor is two fold: first the usual reason that it is a base class, and so needs a virtual destructor to ensure derived type instances referenced through base pointers (or references) are destroyed correctly. Secondly, dynamic_cast relies on RTTI (Run Time Type Information), which only works for types having virtual members (this is because RTTI implementations typically use the vtable which is only present for classes with virtual functions). Note: you may have to use a compiler switch or option to turn on RTTI.

Now the above approach may not be 100% suitable for what you wish, but I hope it at least gives so some ideas for alternatives. Specifically I would have thought in this case, where you might not know in advance the type of the values popped off the stack, that a type discrimination value would be of use (such as an enum having enumerated values such as v_int, v_char etc.), it depends on what you are doing with all this variant data!

C++

All Answers


Answers by Expert:


Ask Experts

Volunteer


Ralph McArdell

Expertise

I am a software developer with more than 15 years C++ experience and over 25 years experience developing a wide variety of applications for Windows NT/2000/XP, UNIX, Linux and other platforms. I can help with basic to advanced C++, C (although I do not write just-C much if at all these days so maybe ask in the C section about purely C matters), software development and many platform specific and system development problems.

Experience

My career started in the mid 1980s working as a batch process operator for the now defunct Inner London Education Authority, working on Prime mini computers. I then moved into the role of Programmer / Analyst, also on the Primes, then into technical support and finally into the micro computing section, using a variety of 16 and 8 bit machines. Following the demise of the ILEA I worked for a small company, now gone, called Hodos. I worked on a part task train simulator using C and the Intel DVI (Digital Video Interactive) - the hardware based predecessor to Indeo. Other projects included a CGI based train simulator (different goals to the first), and various other projects in C and Visual Basic (er, version 1 that is). When Hodos went into receivership I went freelance and finally managed to start working in C++. I initially had contracts working on train simulators (surprise) and multimedia - I worked on many of the Dorling Kindersley CD-ROM titles and wrote the screensaver games for the Wallace and Gromit Cracking Animator CD. My more recent contracts have been more traditionally IT based, working predominately in C++ on MS Windows NT, 2000. XP, Linux and UN*X. These projects have had wide ranging additional skill sets including system analysis and design, databases and SQL in various guises, C#, client server and remoting, cross porting applications between platforms and various client development processes. I have an interest in the development of the C++ core language and libraries and try to keep up with at least some of the papers on the ISO C++ Standard Committee site at http://www.open-std.org/jtc1/sc22/wg21/.

Education/Credentials

©2016 About.com. All rights reserved.