在C++中覆盖虚函数时可以更改返回类型吗?

cam*_*ino 7 c++ virtual overriding function

我遇到了关于覆盖虚函数的问题,实际上,它是关于hessian(一种Web服务协议).

它有一个基类Object和一些派生类:Long,Int,String,...,所有派生类都有一个无虚函数"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_;  
       ...  
   };  
Run Code Online (Sandbox Code Playgroud)

现在我想添加一个函数,比如toString,它可以将Object转换为字符串:

Object *obj  = ...
cout<<obj->toString();
Run Code Online (Sandbox Code Playgroud)

如果我可以将值函数更改为virtual,我只需要在Object中编写一个toString函数,否则,我需要编写一个虚函数toString,并在所有派生类中重写这个函数.

例如

   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());  
       }  

   };  
Run Code Online (Sandbox Code Playgroud)

但我不能写一个虚值函数,因为返回值不能被覆盖.

这个问题有什么好的解决方案吗?

谢谢

Che*_*Alf 8

在C++中覆盖虚函数时可以更改返回类型吗?

仅以非常有限的方式,在(原始)指针或引用返回类型中可以是协变的.

这个问题有什么好的解决方案吗?

嗯,有两个相当不错的解决方案,一个稍微不好的解决方案.

我在这里给你一个稍微不好的解决方案.我给出的一个原因是它很容易理解,或者至少它很容易"复制和修改",即使一个人不太了解它.另一个原因是,其中一个好的解决方案需要一些广泛的通用支持机制,这里没有讨论的余地,另一个好的解决方案(我认为几乎在所有方面都是最好的解决方案)是至少一种,至少当我提出这种解决方案时,已经自动收到了驱动器的支持,只有那个,这里就是SO.我猜这是为这里的多样性付出的代价,多样性是一件非常好的事情:-)但不幸的是,这意味着提供真正的好东西是没有意义的,那么我就会接受负面的代表.

无论如何,代码,基于虚拟继承的优势; 它与在Java或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;
}
Run Code Online (Sandbox Code Playgroud)

如果你LongInt类等非常相似,就像它们看起来那样,考虑只定义一个类模板,或者可能继承这种模板的特化(这也可能有助于避免错误,因为它减少了冗余).

编辑:我现在看到你已经接受了一个答案,这个答案基本上只是我关于模板的最后一个建议.这意味着我已经回答了所提出的问题(针对不同类别的不同类别的解决方案),而你的内容则不那么通用.那好吧.

干杯&hth.,


Mer*_*OWA 3

不,您不能使用虚拟“值”函数在 Object 中写入 toString 并覆盖返回类型。然而,您可以编写一个虚拟的 toString 并使用模板编程技巧完成几乎相同的事情。

class Object
{
public:
  virtual std::string toString();
}


template < class ValueType >
class BasicType : Object
{
  public:
  typedef ValueType basic_type;
  basic_type value() { return value_; }

  std::string toString()
  {
    return some_convert_function( value_ );
  }

  private:
  basic_type value_;
}

typedef BasicType<long long> Long;
typedef BasicType<int>       Int;
Run Code Online (Sandbox Code Playgroud)