можно изменить тип возвращаемого значения при переопределении виртуальной функции в 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;
}
Если ваши Long
и Int
классы и т. Д. Очень похожи, как кажется, рассмотрите возможность определения только одного шаблона класса или, возможно, унаследуйте от специализаций такого шаблона (это также может помочь избежать ошибок, так как это уменьшает избыточность).
РЕДАКТИРОВАТЬ : Теперь я вижу, что вы приняли ответ, который по сути является лишь моим последним предложением о шаблонировании. Это означает, что я ответил на поставленный вопрос (решение для разных, разных классов), а вы имели в виду нечто более общее. Ну хорошо.
Приветствия & hth.,