模板函數原型聲明和定義實現必須放在一起

問題起因是我在一個.h文件中定義模版類,忘了在.cpp中定義函數時如何寫(就是忘了 CLASS<T>::show中的<T>),然後順便在.h中聲明瞭個模板函數(函數原型),又在cpp中定義,結果在主函數中用時,出現錯誤(未定義)。於是搜索,原來總結一句話如下

模版函數在.h中必須定義聲明一塊,都在其中。不能像普通函數一樣,一個.h一個cpp,同樣模板類的函數也不行,只是它可以在類中先聲明,然後在類外定義,但也必須在一個.h中

這裏我又想到一個問題,那麼如果摸板類,如何封裝,只留接口而保密實現呢。
至於原因stackoverflow上有解釋,在最末尾也貼了,其實我覺得就是模版函數和普通函數不一樣,The compiler needs to have access to the entire template definition (not just the signature) in order to generate code for each instantiation of the template, so you need to move the definitions of the functions to your header.

.h

#ifndef QUEUE_H

#define QUEUE_H

#include<iostream>

template<class T>

class FQueue

{

private:

 

    T fq[10];

public:

 

 \

    FQueue(int qs ); //給參數提供默認值

    ~FQueue();

    bool isempty() const;

    bool isfull() const;

    int queuecount() const;

    bool inqueue(const T &item);

    bool dequeue(const T &item);

 

};

 

void show();  //普通函數這樣是沒有問題的

 

//下面這個是原型在這h.定義在cpp

template<class T> void shimobanhwai(T a);

 

//下面這樣是對的,都放在.h文件中

template<class T> void shimobanhnei(T a)

{

     std::cout << "a is " << a << std::endl;

}

#endif // QUEUE_H

 

 

.cpp

#include"queue.h"

#include<iostream>

using namespace std;

template<class T>

FQueue<T>::FQueue(int qs)   //這樣也不行,必須放在.h中,否則當建立對象時還是會出現未定義

{

    T* fqp = new T[qs];

 

}

template<class T>

FQueue<T>::~FQueue()    //class名字後面別忘了加<T>,這是我經常忘的

{}

template<class T>

bool FQueue<T>::isempty() const

{}

template<class T>

bool FQueue<T>::isfull() const

{}

template<class T>

int FQueue<T>::queuecount() const

{}

template<class T>

bool FQueue<T>::inqueue(const T &item)

{}

template<class T>

bool FQueue<T>::dequeue(const T &item)

{}

 

void show()

{

    cout << "Am i right?" << endl;

}

template<class T>

void  shimobanhwai(T a)

{

    cout << "a is " << a << endl;

}

 

 

Main.cpp

#include <iostream>

#include"queue.h"

 

 

using namespace std;

//模板函數、模板類

//新發現,模板不能分.h.cpp

 

int main()

{

 

    shimobanhnei(5);

    //shimobanhwai(5);//出錯

    show();

   // why(3);

    cout << " bye!" << endl;

    cin.clear();  //清楚標誌位

    while (cin.get() != '\n')

        continue;            //清楚輸入流數據

 

    return 0;

}

 


stackoverflow上我覺得比較經典的解釋

Q:

Why can templates only be implemented in the header file?

A:

Because when instantiating a template, the compiler creates a new class with the given template argument. For example:

template<typename T>
struct Foo
{
    T bar;
    void doSomething(T param) {/* do stuff using T */}
};

// somewhere in a .cpp
Foo<int> f; 

When reading this line, the compiler will create a new class (let's call it FooInt), which is equivalent to the following:

struct FooInt
{
    int bar;
    void doSomething(int param) {/* do stuff using int */}
}

Consequently, the compiler needs to have access to the implementation of the methods, to instantiate them with the template argument (in this case int). If these implementations were not in the header, they wouldn't be accessible, and therefore the compiler wouldn't be able to instantiate the template.

A common solution to this is to write the template declaration in a header file, then implement the class in an implementation file (for example .tpp), and include this implementation file at the end of the header.

// Foo.h
template <typename T>
struct Foo
{
    void doSomething(T param);
};

#include "Foo.tpp"

// Foo.tpp
template <typename T>
void Foo<T>::doSomething(T param)
{
    //implementation
}

This way, implementation is still separated from declaration, but is accessible to the compiler.

Another solution is to keep the implementation separated, and explicitly instantiate all the template instances you'll need:

// Foo.h

// no implementation
template <typename T> struct Foo { ... };

//----------------------------------------    
// Foo.cpp
// implementation of Foo's methods

// explicit instantiations
template class Foo<int>;
template class Foo<float>;
// You will only be able to use Foo with int or float

If my explanation isn't clear enough, you can have a look at the C++ FaqLite on this subject.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章