Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
182 views
in Technique[技术] by (71.8m points)

it is possible to change return type when override a virtual function in C++?

I encounter a problems about override virtual functions, in fact,it is about hessian (a web service protocol).

it has a base class Object, and some derived classes : Long,Int,String,...,all derived classes has a no-virtual function "value"

   class Object  
   {  
     ...    
   };  


   class Long :public Object  
   {  
       ...  
   public:  
       typedef long long  basic_type;  
       basic_type value(){return value_;}  
   private:  
       basic_type value_;  
       ...  
   };  


   class Int :public Object  
   {  
      ...  
   public:  
       typedef int basic_type;  
       basic_type value(){return value_;}  
   private:   
       basic_type value_;  
       ...  
   };  

now I want to add a function ,say, toString ,which can convert Object to a string:

Object *obj  = ...
cout<<obj->toString();

if I can change the value function to virtual ,I only need to write a toString function in Object, else, I need to write a virtual function toString, and to override this functions in all derived classes.

for example

   class Object  
   {  
       virtual Type value(); // It seemed that I can't write a function like this,because the Type is different for different derived classes  


       std::string toString()  
       {  
           some_convert_function(value());  
       }  

   };  

but I can't write a virtual value function because of return value can't be override.

is there any good solution for this issue?

Thanks

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

it is possible to change return type when override a virtual function in C++?

Only in a very limited way, in that (raw) pointer or reference return type can be covariant.

is there any good solution for this issue?

Well, there are two fairly good solutions, and one slightly bad solution.

I'm giving you the slightly bad solution here. One reason that I'm giving that is that it's easy to understand, or at least it's quite easy to "copy and modify" even if one doesn't quite understand it. Another reason is that one of the good solutions requires some extensive general support machinery that there's no room for discussing here, and the other good solution (the one that in my opinion is best in nearly every respect) is of a kind that, at least when I have presented that kind of solution, has automatically received drive-by downvotes and only that, here on SO. I guess that that's the price to pay for the diversity here, which diversity is a Very Good Thing :-) But, unfortunately it means that there's no point in offering the real good stuff, I'd be down to negative rep then.

Anyways, code, based on dominance in virtual inheritance; it's about the same as inheriting an implementation of an interface in Java or C#:

#include <iostream>
#include <string>
#include <sstream>

//--------------------------------------- Machinery:

class ToStringInterface
{
public:
    virtual std::string toString() const = 0;
};

template< typename ValueProvider >
class ToStringImpl
    : public virtual ToStringInterface
{
public:
    virtual std::string toString() const
    {
        ValueProvider const&    self    =
            *static_cast<ValueProvider const*>( this );
        std::ostringstream      stream;
        stream << self.value();
        return stream.str();
    }
};

//--------------------------------------- Usage example:

class Object  
    : public virtual ToStringInterface
{  
    // ...    
};  

class Long
    : public Object
    , public ToStringImpl< Long >
{  
public:  
   typedef long long  BasicType;  
   Long( BasicType v ): value_( v ) {}
   BasicType value() const { return value_; }  
private:  
   BasicType value_;  
};  

class Int
    : public Object
    , public ToStringImpl< Int >
{  
public:  
   typedef int BasicType;  
   Int( BasicType v ): value_( v ) {}
   BasicType value() const { return value_; }
private:   
   BasicType value_;  
}; 

int main()
{
    Object const& obj = Int( 42 );
    std::cout << obj.toString() << std::endl;
}

If your Long and Int classes etc. are very similar, as they seem to be, consider defining just one class template, or perhaps inherit from specializations of such a template (this might also help avoid bugs, since it reduces redundancy).

EDIT: I see now that you have accepted an answer that is essentially just my last suggestion about templating. That means that I've answered the question as posed (a solution for distinct, different classes) while you had something less general in mind. Oh well.

Cheers & hth.,


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...