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


Автор: Kuvaldis 17.6.2006, 11:49
Буду рад любой помощи. Проблема в следующем. Если 1) нижеприведенный код находится в одном файле или 2)  вместо подключения hpp подключаю cpp (что не есть гуд) то все работает.
иначе выдается ошибка линкера (делаю подключение header-файла, как всегда, что всегда (!) до этого работало как на С, так и для простых классов С++)
В книгах, что я нашел по этому поводу написано ,что я прав (хотя как Builder 6, так и VC 6 так не считают)

ЗАГОЛОВОЧНЫЙ ДЛЯ ШАБЛОНА 

//---------------------------------------------------------------------------
#include <iostream>
using namespace std;
//---------------------------------------------------------------------------
const int DefaultSize = 10;
//---------------------------------------------------------------------------
template <class T> class Array;    
template <class T> extern ostream & operator << (ostream & output, 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]; } 
     int GetSize() const { return itsSize; }
     
     friend ostream & operator << <> (ostream & output, Array<T> & theArray);
};
//----------------------------------------------------------------

РЕАЛИЗАЦИЯ ДЛЯ ЗАГОЛОВОЧНОГО ШАБЛОНА 

//---------------------------------------------------------------------------
#include "Array.hpp"
#include <iostream>
using namespace std;
//---------------------------------------------------------------------------
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;
}
//---------------------------------------------------------------------------
template <class T>
ostream & operator <<  (ostream & output, Array<T> & theArray)
{
   for(int i = 0; i < theArray.itsSize; i++)
      output << "Array[" << i << "] = " << theArray[i] << endl;
   return output;   
}
//---------------------------------------------------------------------------


MAIN

//---------------------------------------------------------------------------
#include <iostream>
#include "Array.hpp"
//  #include "Array.cpp"   // ЕСЛИ подкючить этот файл вместо hpp то все зер гуд
using namespace std;
//---------------------------------------------------------------------------
#pragma argsused
#pragma hdrstop
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
    int    i, n;
    Array <int> theArray(3);

    n = theArray.GetSize();
    for(i = 0; i < n; i++)
      theArray[i] = i * 2;
    cout << theArray;
    
    cin >> i;
    return 0;
}
//---------------------------------------------------------------------------

P.S. что-то не получается пользоваться тегами, чтобы код симпатичный был, мож кто скажет как?


 

Автор: DeadSoul 17.6.2006, 12:22
Цитата(Kuvaldis @  17.6.2006,  11:49 Найти цитируемый пост)
P.S. что-то не получается пользоваться тегами, чтобы код симпатичный был, мож кто скажет как?

Нажми на кнопку "Код" и располагай свой ков внутри появившихся тегов.

По сути: ВЕСЬ шаблон, включая РЕАЛИЗАЦИЮ методов должен находится в h-файле 

Автор: LPBOY 17.6.2006, 12:30
Шаблоны вместе со всей своей реализацией должны находиться в *.h файле. Никаких переносов реализации в *.cpp, как с обычными классами/функциями, не допускается.
Есть правда ключевое слово export, которое позволяет это делать, но его поддерживают только компиляторы comeau (и новые версии intel compiler кажется).

Или для каждой специализации шаблона, в хедере можешь написать
Код

template class Array<int>;

если память не изменяет.
Цитата(Kuvaldis @  17.6.2006,  11:49 Найти цитируемый пост)
P.S. что-то не получается пользоваться тегами, чтобы код симпатичный был, мож кто скажет как?

Щелкаешь по кнопке "Код", появляются теги
[сode=cpp]

[/сode]
между ними пишешь код. smile 

Автор: Kuvaldis 17.6.2006, 12:34
По-моему суть header-файла тогда теряется:  предоставить интерейс класса (шаблона)
Хотя с помещением реализации из cpp в header прогамма работает, но.. выдает интересный warning 
[C++ Warning] Array.cpp(4): W8058 Cannot create pre-compiled header: header incomplete
Хотелось бы для данной программы все таки 3 файла smile

Добавлено @ 12:37 
Sorry LPBOY, присал сообщение как раз в тот момент когда ты мне отписал (ответ твой понял) Спасибо. Хотя warning все равно интересный (см. выше) 

Автор: Kuvaldis 17.6.2006, 13:20
Хорошо, описываем реализацию в header-файле, но не в теле класса, а  отдельно: теперь Builder компилирует, а visual 6 выдает ошибку:

header:

Код

//---------------------------------------------------------------------------
#include <iostream>
using namespace std;
//---------------------------------------------------------------------------
const int DefaultSize = 10;
//---------------------------------------------------------------------------
template <class T> class Array;    
template <class T> ostream & operator << (ostream & output, 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);
};
//---------------------------------------------------------------------------
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;
}
//---------------------------------------------------------------------------


MAIN

Код

//---------------------------------------------------------------------------
#include <iostream>
#include "Array.hpp"
//#include "Array.cpp"
using namespace std;
//---------------------------------------------------------------------------
#pragma hdrstop
//---------------------------------------------------------------------------
int main(int argc, char* argv[])
{
    int    i, n;
    Array <int> theArray(3);

    n = theArray.GetSize();
    for(i = 0; i < n; i++)
      theArray[i] = i * 2;
    cout << theArray;
    
    cin >> i;
    return 0;
}
//---------------------------------------------------------------------------
template <class T>
ostream & operator << (ostream & output, Array<T> & theArray)
{
   for(int i = 0; i < theArray.itsSize; i++)
      output << "Array[" << i << "] = " << theArray[i] << endl;
   return output;   
}
//---------------------------------------------------------------------------


Ошибка следующая: 
Compiling...
MyTemplate.cpp
G:\Learning\Programming\C\Visual\Temp_1\MyTemplate.cpp(26) : error C2248: 'itsSize' : cannot access private member declared in class 'Array<int>'
  
при реализации функции-шаблона, которая является дружественной и , следовательно, ИМЕЕТ доступ к "private member declared in class 'Array<int>'"
Или я не прав?
    

Автор: LPBOY 17.6.2006, 13:37
У меня на VC7.1 скомпилировалась, правда не слинковалась. smile
После добавления угловых скобочек
friend ostream & operator << <> (ostream & output, Array<T> & theArray);
работает, выдает
Код

Array[0] = 0
Array[1] = 2
Array[2] = 4
 

Автор: DeadSoul 17.6.2006, 14:05
Цитата(Kuvaldis @  17.6.2006,  12:34 Найти цитируемый пост)
По-моему суть header-файла тогда теряется:  предоставить интерейс класса (шаблона)

Читай книгу Вандервуда по шаблонам. У шаблона есть принципиальные отличия от класса

Цитата(Kuvaldis @  17.6.2006,  13:20 Найти цитируемый пост)
G:\Learning\Programming\C\Visual\Temp_1\MyTemplate.cpp(26) : error C2248: 'itsSize' : cannot access private member declared in class 'Array<int>'

Тебе по-русски сказали "Не могу получить доступ к приватной переменной" 

Автор: LPBOY 17.6.2006, 14:09
Цитата(DeadSoul @  17.6.2006,  14:05 Найти цитируемый пост)
Тебе по-русски сказали "Не могу получить доступ к приватной переменной" 

Так он там к функции русским по белому приписал "friend".  

Автор: Kuvaldis 17.6.2006, 14:35
Выводы:
1) компилятор VC 6 немного  глючный (1 раз - случайность, 2 - тенденция, это уже третий - и последний : закономерность)

2) реализация шаблона должна быть в том же header-файле 

2) LPBOY, будь у меня 100 постов, увеличил бы тебе репутацию, а так, огромнейшее спасибо
(компилируется в visual dtudio 2005 тоже) 

Автор: Earnest 19.6.2006, 08:40
Цитата(Kuvaldis @  17.6.2006,  15:35 Найти цитируемый пост)
 компилятор VC 6 немного  глючный 

Не глючный, а не совсем соответствует стандарту, в частности, в том, что касается шаблонов. Это так. 
LPBOY, + за Kuvaldis.  

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