2010-04-21 4 views
2

Я применил указатели подсчета ссылок (например, SP), и у меня возникли проблемы с полиморфизмом, который, как я думаю, не должен был быть.Умные указатели и полиморфизм

В следующем коде:

SP<BaseClass> foo() 
    { 
     // Some logic... 
     SP<DerivedClass> retPtr = new DerivedClass(); 
     return retPtr; 
    } 

DerivedClass наследует от BaseClass. С нормальными указателями это должно было сработать, но с умными указателями он говорит "cannot convert from 'SP<T>' to 'const SP<T>&", и я думаю, что это относится к конструктору копирования умного указателя.

Как разрешить этот вид полиморфизма с указателем подсчета ссылок? Я был бы признателен за примеры кода, потому что, очевидно, я делаю что-то неправильно здесь, если у меня возникла эта проблема.

PS: Пожалуйста, не говорите мне, чтобы использовать стандартную библиотеку с интеллектуальными указателями, потому что это невозможно в данный момент.

+0

Пожалуйста, разместите код для конструктора копирования. – Danvil

+0

При чтении сообщений об ошибках шаблона важно заметить, что означает 'T' в каждой позиции. Вероятно, ошибка, возможно, говорит о том, что что-то вроде не может конвертировать из 'SP с [T = DerivedClass] в const SP & с [T = BaseClass]', что дополнительная часть информации составляет половину пути к решению. –

ответ

6

довольно очевидна:

SP<DerivedClass> retPtr = new DerivedClass(); 

должно быть:

SP<BaseClass> retPtr = new DerivedClass(); 
+2

Преобразование SP в SP не должно быть проблемой с реализацией умного указателя. – Danvil

+0

Это исправляет специфическую проблему в 'foo()', но это не делает естественный синтаксис в других местах, где может потребоваться преобразование. – Gorpik

+1

@Danvil: преобразование не является проблемой, вы не можете изменить тип возвращаемого значения в перегруженной функции, за исключением ограниченных случаев (ковариантные ссылки и указатели), поэтому бессмысленно даже создавать «SP» неправильного типа. Этот ответ является самым простым: создайте объект возвращаемого типа. –

0

Почему бы не добавить оператор присваивания шаблона:

template <class Base> 
class SP 
{ 
    ... 

    template<class Derived> 
    operator = (SP<Derived>& rhs) 
    { 
     ... 

(и, возможно, конструктор копирования, тоже)?

4

Вы должны добавить неявное преобразование конструктора SP<T>:

template<class T> 
struct SP { 
    /// ...... 
    template<class Y> 
    SP(SP <Y> const & r) 
    : px(r.px) // ... 
    { 
    } 

    //.... 
private: 
    T * px; 
} 
+0

Конструктор шаблонов никогда не является конструктором копирования. Конструктор копирования не поможет; это неявный конструктор преобразования. –

+0

@Charles. Правильно. Не важно. –

0

В дополнении к конструктору копирования:

SP(const SP<T>& ref); 

вам нужен конструктор преобразования:

template<typename T2> 
SP(const SP<T2>& ref); 

В противном случае, компилятор не знает, как построить SP<BaseClass> от SP<DerivedClass>; для него они не связаны.

Конструктор преобразования довольно тривиален, поскольку внутри вы можете автоматически преобразовывать *DerivedClass в *BaseClass. Код может быть очень похож на код для конструктора копирования.