歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

C++模板函數聲明定義分離編譯錯誤詳解

今天看到accelerated c++上有個簡單的vector容器的實現Vec,就再vs2008上編譯了下:

/////  Vec.h

 

#ifndef GUARD_VEC_H

#define GUARD_VEC_H

 

#include <iostream>

#include <iterator>

#include <memory>

//#include <xmemory>

 

template <class T>

class Vec

{

public:

    typedef T* iterator;

    typedef const T* const_iterator;

    typedef size_t size_type;

    typedef T value_type;

    typedef T& reference;

    typedef const T& const_reference;

 

    Vec() {create();} //默認的構造函數

    explicit Vec(size_type n,const T& t=t()) {create(n,t);} //單參數或者兩個參數構造函數

    Vec(const Vec& v) {create(v.begin(),v.end());} //拷貝構造函數

    Vec& operator=(const Vec&);  //賦值構造函數

    ~Vec() {uncreate();} //析構函數

   

    size_type size() { return avail-data; } //定義類的大小,ptrdiff_t自動轉化成size_t

    void push_back(const T& t)

    {

        if (avail==limit)

        {

            grow();

        }

        unchecked_append(t);

    }

    //重載【】

    T& operator[] (size_type i) { return data[i]; }

    const T& operator[] (size_type i) const { return data[i]; }

    //定義begin和end,都有兩個版本

    iterator begin() {return data;}

    const_iterator begin() const {return data;}

    iterator end() {return avail;}

    const_iterator end() const {return avail;}

protected:

private:

    iterator data; //Vec中得初始值

    iterator avail; //Vec中得結束值

    iterator limit; //Vec中空間分配的結束值

    std::allocator<T> alloc; //注意此處std

    //創造函數,負責內存管理

    void create();

    void create(size_type,const T&);

    void create(const_iterator,const_iterator);

    //銷毀元素,返回內存

    void uncreate();

    //支持push_back函數

    void grow();

    void unchecked_append(const T&);

};

 

#endif


////  Vec.cpp

 

#include <iostream>

#include "Vec.h"

//#pragma comment(lib,"ws2_32.lib")

 

using namespace std;

 

//拷貝構造函數

template <class T>

Vec<T>& Vec<T>::operator=(const Vec& v)

{

    if (&v!=this) //檢查是否為自我賦值,很重要,必須有

    {

        uncreate(); //清空左值的元素

        create(v.begin(),v.end()); //拷貝元素到左值

    }

    return *this;

}

 

 

 

//push_back函數中內存增長策略函數

template <class T>

void Vec<T>::grow()

{

    size_type new_size=max(2*(limit-data),ptrdiff_t(1)); //防止剛開始內存空間為0的情況

    iterator new_data=alloc.allocate(new_size); //返回首地址

    //把前兩個參數指定的元素復制給第三個參數表示的目標序列,返回末尾元素的下一個迭代器

    iterator new_avail=uninitialized_copy(data,avail,new_data);

    uncreate(); //釋放原先的空間

 

    data=new_data;

    avail=new_avail;

    limit=data+new_size;

}

 

//向申請的內存中添加元素

template <class T>

void Vec<T>::unchecked_append(const T& val)

{

    //在未初始化的空間構建一個對象,參數1插入對象的位置指針,參數2需要添加的對象

    alloc.construct(avail++,val);

}

 

 

//申請內存的函數create

template <class T>

void Vec<T>::create()

{

    data=avail=limit=0;

}

template <class T>

void Vec<T>::create(size_type n,const T& val)

{

    data=alloc.allocate(n); //申請內存空間,但是不初始化

    limit=avail=data+n;

    uninitialized_fill(data,limit,val); //進行初始化

}

template <class T>

void Vec<T>::create(const_iterator i,const_iterator j)

{

    data=alloc.allocate(j-i);

    limit=avail=uninitialized_copy(i,j,data);

}

 

//回收內存

template <class T>

void Vec<T>::uncreate()

{

    if (data) //如果data是0,我們不需要做什麼工作

    {

        iterator it=avail;

        while (it!=data)

            alloc.destroy(--it); //銷毀沒個元素,為了與delete行為一致,采用從後向前遍歷

        alloc.deallocate(data,limit-data); //內存釋放,函數需要一個非零指針

                                          //因此,檢測data是否為零

    }

    data=limit=avail=0;

}


//// 測試的main函數

 

#include <iostream>

#include "Vec.h"

using namespace std;

int main()

{

    Vec<int> a;

    Vec<int> b;

    a.push_back(12);

    b=a;

    return 0;


 
結果編譯後出現下面錯誤:
 
1>------ 已啟動生成: 項目: Accelerated, 配置: Debug Win32 ------
1>正在編譯...
1>Vec.cpp
1>Vec_example.cpp
1>正在生成代碼...
1>正在鏈接...
1>Vec_example.obj : error LNK2001: 無法解析的外部符號 "public: class Vec<int> & __thiscall Vec<int>::operator=(class Vec<int> const &)" (??4?$Vec@H@@QAEAAV0@ABV0@@Z)
1>Vec_example.obj : error LNK2001: 無法解析的外部符號 "private: void __thiscall Vec<int>::create(void)" (?create@?$Vec@H@@AAEXXZ)
1>Vec_example.obj : error LNK2001: 無法解析的外部符號 "private: void __thiscall Vec<int>::uncreate(void)" (?uncreate@?$Vec@H@@AAEXXZ)
1>Vec_example.obj : error LNK2001: 無法解析的外部符號 "private: void __thiscall Vec<int>::unchecked_append(int const &)" (?unchecked_append@?$Vec@H@@AAEXABH@Z)
1>Vec_example.obj : error LNK2001: 無法解析的外部符號 "private: void __thiscall Vec<int>::grow(void)" (?grow@?$Vec@H@@AAEXXZ)
1>E:\360data\重要數據\我的文檔\Visual Studio 2008\Projects\Accelerated\Debug\Accelerated.exe : fatal error LNK1120: 5 個無法解析的外部命令
1>生成日志保存在“file://e:\360data\重要數據\我的文檔\Visual Studio 2008\Projects\Accelerated\Accelerated\Debug\BuildLog.htm”
1>Accelerated - 6 個錯誤,0 個警告
========== 生成: 成功 0 個,失敗 1 個,最新 0 個,跳過 0 個 ==========
 
上面問題不知道怎麼解決,就開始google解決方案: 模板不支持分離編譯, 把你模板類的聲明和實現放到.h文件裡面 。按照這個說的把.h和.cpp文件合並後,果然可以了。

Copyright © Linux教程網 All Rights Reserved