[英]it is possible to change return type when override a virtual function in C++?
我遇到了關於覆蓋虛函數的問題,實際上,它是關於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_;
...
};
現在我想添加一個函數,比如toString,它可以將Object轉換為字符串:
Object *obj = ...
cout<<obj->toString();
如果我可以將值函數更改為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());
}
};
但我不能寫一個虛值函數,因為返回值不能被覆蓋。
這個問題有什么好的解決方案嗎?
謝謝
僅以非常有限的方式,在(原始)指針或引用返回類型中可以是協變的。
嗯,有兩個相當不錯的解決方案,一個稍微不好的解決方案。
我在這里給你一個稍微不好的解決方案。 我給出的一個原因是它很容易理解,或者至少它很容易“復制和修改”,即使一個人不太了解它。 另一個原因是,其中一個好的解決方案需要一些廣泛的通用支持機制,這里沒有討論的余地,另一個好的解決方案(我認為幾乎在所有方面都是最好的解決方案)是至少一種,至少當我提出這種解決方案時,已經自動收到了驅動器的支持,只有那個,這里就是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;
}
如果您的Long
和Int
類等非常相似,可以考慮僅定義一個類模板,或者可能繼承此類模板的特化(這可能也有助於避免錯誤,因為它可以減少冗余)。
編輯 :我現在看到你已經接受了一個答案,這個答案基本上只是我關於模板的最后一個建議。 這意味着我已經回答了所提出的問題(針對不同類別的不同類別的解決方案),而你的內容則不那么通用。 那好吧。
干杯&hth。,
不,您不能使用虛擬“值”函數在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;
不幸的是,你不能通過返回值重載C ++中的函數。 你可以做什么,如果你有適合所有類型的some_convert_function
就可以創建一個看起來像這樣的模板函數:
template<typename T>
std::string toString(T const& t)
{
return some_convert_function<T>(t);
}
關於@MerickOWA評論,這是另一種解決方案,不需要任何額外的模板機制。
既然你想要在所有類中實現一個虛擬的“value()”方法,我已經擴展了這個想法(通常,在這種框架中,你有很多類似的“基本”方法,所以我已經使用宏來為我編寫它,它不是必需的,它只是更快,更不容易出錯。
#include <iostream>
#include <string>
#include <sstream>
struct Object
{
std::string toString() const { std::ostringstream str; getValue(str); return str.str(); }
virtual void getValue(std::ostringstream & str) const { str<<"BadObj"; }
};
// Add all the common "basic & common" function here
#define __BoilerPlate__ basic_type value; void getValue(std::ostringstream & str) const { str << value; }
// The only type specific part
#define MAKE_OBJ(T) typedef T basic_type; __BoilerPlate__
struct Long : public Object
{
MAKE_OBJ(long long)
Long() : value(345) {}
};
struct Int : public Object
{
MAKE_OBJ(long)
Int() : value(3) {}
};
int main()
{
Object a;
Long b;
Int c;
std::cout<<a.toString()<<std::endl; // BadObj
std::cout<<b.toString()<<std::endl; // 345
std::cout<<c.toString()<<std::endl; // 3
return 0;
}
顯然,技巧是在std :: ostringstream類中接受任何參數類型(long long,long等等)。 由於這是標准的C ++實踐,因此無關緊要。
您不能使用不同的返回類型覆蓋函數; 最接近的是隱藏父類中的函數,在派生類中使用不同的函數。 但那不是你想要的,因為兩者將是不同的功能,完全不相關。
假設您需要在每個派生類中創建一個新的toString
函數,這是正確的 - 這就是多態性的全部內容。
我不認為你是正確的方式。 雖然在某些情況下可以更改虛函數的返回類型,但請考慮:您的函數是如何使用的? 如果它是虛擬的,那么用戶將使用基類進行更改。 因此,他們不知道你的班級的實際類型是什么,因此他們不知道期望什么類型。 所以:
virtual std::string getStringValue()
,如果適用,它會給你一個字符串)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.