2014-12-24 2 views
0

Обычно я знаю, как обращаться с перекрестными ссылками, но здесь я застрял.Перекрестные ссылки при использовании параметров шаблона

Пусть умный класс указатель:

template< typename T > 
SharedPointer 
{ 
    T * _ptr; 
}; 

И:

class Array; 

class Value 
{ 
    SharedPointer<Array> _pa; 
}; 

И:

class Array 
{ 
    Value someFunc(); 
} 

Здесь я имею предупреждения в классе SharedPointer высказывании, что я удаление указателей на объекты неполного типа, которые, как я полагаю, обусловлено форвардным объявлением.

Warning 2 warning C4150: deletion of pointer to incomplete type 'script::Array'; no destructor called c:\XXXXX\SharedPointer.h 77 

Что я могу сделать, чтобы решить эту проблему? Единственное решение я вижу переписывает весь класс SharedPointer к чему-то вроде:

template< typename pT > 
SharedPointer 
{ 
    pT _ptr; 
}; 

И использовать его как это вместо:

SharedPointer< Array * > 

Я хотел бы избежать перезаписи этого класса, если это возможно. Есть ли другое решение? Спасибо :)

EDIT: Вот реальный исходный код:

class Value 
{ 
    PUBLIC enum type_e 
    { 
     E_NULL, 

     E_INT, 

     E_FLOAT, 

     E_STRING, 

     E_ARRAY, 

     E_MAP, 

     E_FUNCTION, 

     E_REFERENCE // TODO For functions like fn(scalar & val) 
    }; 

    PRIVATE union 
    { 
     int _i; 

     float _f; 

     std::string * _ps; 

     IFunction * _pf; 
    }; 

    PRIVATE SharedPointer<Array> _pa; 

    PRIVATE SharedPointer<Map> _pm; 

    PRIVATE SharedPointer<Value> _ref; 

    PRIVATE type_e _type; 

    PUBLIC Value(); 

    PUBLIC Value(bool b); 

    PUBLIC Value(int i); 

    PUBLIC Value(float f); 

    PUBLIC Value(const std::string & s); 

    PUBLIC Value(SharedPointer<Array> pa); 

    PUBLIC Value(SharedPointer<Map> pm); 

    PUBLIC Value(IFunction * pf); 

    PUBLIC Value(SharedPointer<Value> ref); 

    PUBLIC Value(const Value & v); 

    PUBLIC ~Value() { } 

    PUBLIC Value operator + (const Value & v) const; 

    PUBLIC Value operator - (const Value & v) const; 

    PUBLIC Value operator * (const Value & v) const; 

    PUBLIC Value operator/(const Value & v) const; 

    PUBLIC Value operator % (const Value & v) const; 

    PUBLIC Value operator^(const Value & v) const; 

    PUBLIC Value operator << (const Value & v) const; 

    PUBLIC Value operator -() const; 

    PUBLIC Value operator && (const Value & v) const; 

    PUBLIC Value operator || (const Value & v) const; 

    PUBLIC Value xor(const Value & v) const; 

    PUBLIC Value operator !() const; 

    PUBLIC Value & operator = (const Value & v); 

    PUBLIC Value operator() (Scope & scope, const std::vector<Value> & args) const; 

    PUBLIC Value & getRef(const Value & v) const; 

    PUBLIC Value getCpy(const Value & v) const; 

    PUBLIC inline type_e getType() const throw() { return _type; } 

    PUBLIC inline bool isNull() const throw() { return E_NULL == _type; } 

    PUBLIC inline bool isInt() const throw() { return E_INT == _type; } 

    PUBLIC inline bool isFloat() const throw() { return E_FLOAT == _type; } 

    PUBLIC inline bool isString() const throw() { return E_STRING == _type; } 

    PUBLIC inline bool isArray() const throw() { return E_ARRAY == _type; } 

    PUBLIC inline bool isMap() const throw() { return E_MAP == _type; } 

    PUBLIC inline bool isFunction() const throw() { return E_FUNCTION == _type; } 

    PUBLIC inline bool isReference() const throw() { return E_REFERENCE == _type; } 

    PUBLIC inline bool isNumeric() const throw() { return E_INT == _type || E_FLOAT == _type; } 

    PUBLIC type_e toNumeric(int & asInt, float & asFloat) const; 

    PUBLIC std::string toString() const; 

    PUBLIC operator bool() const throw(); 
}; 

class Array 
{ 
    PRIVATE std::vector<Value> _items; 

    PUBLIC Array(const std::vector<Value> & items); 

    PUBLIC ~Array(); 

    PUBLIC Value & getRef(int index); 

    PUBLIC Value getCpy(int index) const; 

    PUBLIC int getSize() const; 
}; 


template< typename T > 
class SharedPointer 
{ 
    template< typename U > 
    friend class SharedPointer; 

    PRIVATE T * p; 

    PRIVATE size_t * c; 

    PUBLIC SharedPointer() 
     : p() 
     , c() { } 

    PUBLIC explicit SharedPointer(T * s) 
     : p(s) 
     , c(new size_t(1)) { } 

    PUBLIC SharedPointer(const SharedPointer & s) 
     : p(s.p) 
     , c(s.c) 
    { 
     if(this->c) 
     { 
      ++*(this->c); 
     } 
    } 

    PUBLIC SharedPointer & operator = (const SharedPointer & s) 
    { 
     if(this != & s) 
     { 
      this->clear(); 

      this->p = s.p; 
      this->c = s.c; 

      if(this->c) 
      { 
       ++*(this->c); 
      } 
     } 
     return *this; 
    } 

    PUBLIC template< typename U > 
    SharedPointer(const SharedPointer<U> & s) 
     : p(s.p) 
     , c(s.c) 
    { 
     if(c) 
     { 
      ++*(this->c); 
     } 
    } 

    PUBLIC ~SharedPointer() 
    { 
     this->clear(); 
    } 

    PUBLIC void clear() 
    { 
     if(this->c) 
     { 
      if(*(this->c) == 1) 
      { 
       delete this->p; 
      } 
      if(! --*(this->c)) 
      { 
       delete this->c; 
      } 
     } 

     this->c = NULL; 
     this->p = NULL; 
    } 

    PUBLIC T * get() const 
    { 
     return this->c ? this->p : NULL; 
    } 

    PUBLIC T * operator ->() const 
    { 
     return this->get(); 
    } 

    PUBLIC T & operator *() const 
    { 
     return *(this->get()); 
    } 
}; 
+0

Определите 'Array' перед' Value'. Вперед объявите 'значение' перед определением' Array'. – juanchopanza

+0

Я не могу, потому что для определения массива требуется значение. – Virus721

+0

'Array' требуется только объявление fwd' Value'. – juanchopanza

ответ

2

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

class Value 
{ 
    SharedPointer<Array> _pa; 
    ~Value() { //This will end up calling the destructor for `_pa`. To do that, if needs `Array` to be a completely defined type. } 
}; 

сделать деструктор явно и переместить его в файл CPP. Обратите внимание, что вы можете использовать ключевое слово use the default для определений, встречающихся вне класса.

+1

Вы говорите о '~ Value'. – Jarod42

+0

Извините, я не опубликовал весь код, чтобы этот пример был простым, но Value имеет деструктор. Однако массив не работает. Я добавил деструктор в Array, и предупреждение было удалено. Я не знаю, почему. Я отправлю реальный код. – Virus721

+0

@ Virus721 После просмотра вашего кода, хотя у вас есть '~ Value', вы имеете его в файле заголовка и, следовательно, у него нет доступа к полному определению' Array'. Просто объявите его в заголовке и переместите определение в cpp. – Pradhan