Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Специализированный конструктор шаблона


Автор: Kuvaldis 17.6.2006, 20:02
Наверное, модератор меня уже не любит. За 2 дня 3 вопрос по шаблонам. Читаю книгу Либерти "С++ за 21 день".
На этот раз, надеюсь в последний, такая проблема. Использование специализированного конструктора класса шаблона.

template <class T>
Array<T>::Array(int size) : itsSize(size)
{
   pType = new T[size];
   for(int i = 0; i < size; i++)
      pType[i] = 0;

 
   в этом месте неявно size раз вызывается конструктор класса Т при создании шаблона
      Но для некоторых классов инициализация происходит на этапе pType = new T[size] (зависит от конструктора 
      класса). Чтобы этот процесс оптимизировать, Либерти приводит такое решение для конкретного класса
  Array<Animal>::Array(int AnimalSize) : itsSize(AnimalSize)
{
   pType = new Animal[AnimalSize];
}

   Ни в Builder 6, ни в visual 6 и 2005 программа не работает. Хотел было плюнуть, но очень хочется разобраться

код

Код

//---------------------------------------------------------------------------
#include <iostream>
using namespace std;
//---------------------------------------------------------------------------
const int DefaultSize = 10;
//---------------------------------------------------------------------------
class Animal;
ostream & operator << (ostream & output, const Animal & theAnimal);
//---------------------------------------------------------------------------
class Animal
{
  protected:
     int itsWeight;
  public:
     // constructors
     Animal() : itsWeight(0) {}
     Animal(int weight) : itsWeight(weight) {}
     ~Animal() {}
     // access methods
     int GetWeight() const { return itsWeight; }
     void SetWeight(int weight) { itsWeight = weight; }    

     friend ostream & operator << (ostream & output, const Animal & theAnimal);
};
//---------------------------------------------------------------------------
template <class T> class Array;
template <class T> ostream & operator << (ostream & output, const Array<T> & theArray);
//---------------------------------------------------------------------------
template <class T>
class Array
{
  private:
     T*  pType;
     int itsSize;
  public:
     // constructors   
     Array(int size = DefaultSize);   
     Array(const Array & rhs);
     ~Array() { delete [] pType; } 
     // operators
     Array & operator = (const Array & theArray);
     T & operator [] (int offset) { return pType[offset]; }
     const T & operator [] (int offset) const { return pType[offset]; } 
     // access methods
     int GetSize() const { return itsSize; }    

     friend ostream & operator << <> (ostream & output, Array<T> & theArray);
};
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
    int    i;
    Array <int> theArray;
    Array <Animal> theZoo;
   
    cout << "\nThe Array: \n" << theArray;
    cout << "\nThe Zoo: \n" << theZoo;
    
    cin >> i;
    return 0;
}
//---------------------------------------------------------------------------
ostream & operator << (ostream & output, const Animal & theAnimal)
{
   output << theAnimal.itsWeight;
   return output;
}
//---------------------------------------------------------------------------
template <class T>
ostream & operator << (ostream & output, const Array<T> & theArray)
{
   for(int i = 0; i < theArray.itsSize; i++)
      output << "Array[" << i << "] = " << theArray[i] << endl;
   return output;   
}
//---------------------------------------------------------------------------

template <class T>
Array<T>::Array(const Array & rhs)
{
   itsSize = rhs.itsSize;
   pType = new T[itsSize];
    for(int i = 0; i < itsSize; i++)
       pType[i] = rhs[i];
}
//---------------------------------------------------------------------------
template <class T>
Array<T> & Array<T>::operator = (const Array & theArray)
{
   if(this == &theArray)
     return *this;
   itsSize = rhs.itsSize;
   delete [] pType;
   pType = new T[itsSize];
   for(int i = 0; i < itsSize; i++)
       pType[i] = theArray[i];
   return *this;
}
//---------------------------------------------------------------------------
template <class T>
Array<T>::Array(int size) : itsSize(size)
{
   pType = new T[size];
   for(int i = 0; i < size; i++)
      pType[i] = 0;

/* в этом месте неявно size раз вызывается конструктор класса Animal при создании шаблона  из 
  его объектов, для этого, следуя главе специализированные функции шаблона книги "С++ за 21 день"
  используем нижеприведенный конструктор, но.. где ошибка?
  */
}
//---------------------------------------------------------------------------

// !!!!!!!!!!!!!!!!!!! problem HERE

Array<Animal>::Array(int AnimalSize) : itsSize(AnimalSize)
{
   pType = new Animal[AnimalSize];
}
//---------------------------------------------------------------------------

 

Автор: Daevaorn 17.6.2006, 22:08
Kuvaldis
Код

template<> //!!!!!!
Array<Animal>::Array(int AnimalSize) : itsSize(AnimalSize)
{
    pType = new Animal[AnimalSize];
}

Данная специализация должна быть до main 

Автор: Kuvaldis 18.6.2006, 14:54
1. Daevaorn, спасибо за ответ. Наберу 100 постов, добавлю тебе репутацию.
2. Получается, что если у меня шаблон описан в отдельном header-файле, а класс Animal в головном cpp, то специализацию придется описывать в головном cpp? 
 

Автор: Athlon 18.6.2006, 16:15
Я что-то не пойму, зачем в конструктор шаблона зашивать инициализацию, более логично сделать для этого отдельную фукцию примерно так:
Код

template <class T>    
Array<T>::Array(int size) : itsSize(size)    
{
    pType = new T[size];
}

template <class T>    
void Array<T>::init(T init_value)    
{
    for(int i = 0; i < itsSize; i++)    
        pType[i] = init_value;    
}

При этом в конструкторе шаблона вызывается конструктор класса T без параметров, а в функции init инициализируется конкретным значением, или в данном примере речь идет не о том? 

Автор: Kuvaldis 18.6.2006, 18:21
Athlon, проблема в том, что если у нас создается  шаблонный класс Array, по умолчанию инициализирующийся нулями. Это происходит в цикле. Но для текоторых классов параметров (например, для Animal, данный цикл излишний, так как ницициализация нужная происходит во время создания массива в памяти (через конструктор класса Animal) 

pType = new T[size];

а в цикле идет pType = 0. Это равносильно pType = (T) 0;
Но что значит Animal = 0?  itsWeight = 0; Что делается до этого конструктором.
Именно для оптимизации данной ситуации и нужен спец. конструктор (извини за сумбурный ответ) 

Автор: Athlon 18.6.2006, 21:29
Дык я о том и говорю - пусть в конструкторе шаблона вызывается конструктор без аргументов класса T (Animal), а если нужно инициализировать весь массив конкретным значением, то делать это нужно отдельной функой, например init (см. предидущий пост). А для того чтобы init нормально работала, нужно чтобы у внутренего класса (T или Animal) был перегружен оператор присваивания(если генерируемый компилятором не годится).
Т.е я хочу сказать, что шаблон должен быть максимально универсальным, а если его нужно подстраивать под каждый класс, то зачем такой шаблон нужен? Надеюсь понятна моя точка зрения  smile  

Автор: MAKCim 18.6.2006, 22:03
Цитата

а если его нужно подстраивать под каждый класс, то зачем такой шаблон нужен? 

в том то и дело, что шаблон универсален и есть одно исключение для Animal
для чего по-твоему частичная/полная специализация шаблона нужна? 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)