C++模版函数声明和定义分离导致的错误

在尝试将C++模板函数的声明和定义分别放在.h和.cpp文件时,遇到了编译错误LNK2019。原因是模板函数不支持分离编译,其声明和定义必须在同一个头文件中。为解决此问题,将模板函数的定义移至头文件,并创建新的头文件BasicAlgorithmsImplement.h来包含模板函数的定义,从而避免编译错误。

最近看算法书,想写一些通用的函数实现那些基本的算法,结果第一个就出问题了,如题目说的,C++中把模版函数的声明和定义分别写在了.h和.cpp文件中,导致编译出错。具体是这样的:

BasicAlgorithms.h文件:

#ifndef BASIC_ALGORITHMS_H
#define BASIC_ALGORITHMS_H
#include "stdafx.h"
#include <vector>
using namespace std;

class BasicAlgorithms
{
public:
    template<typename Type> void InsertionSort(vector<Type> &);
};
#endif

然后在BasicAlgorithms.cpp文件中实现了InsertionSort()函数:

#include "stdafx.h"
#include "BasicAlgorithms.h"

template <typename Type>
void BasicAlgorithms::InsertionSort(vector<Type> &vec_to_sort)
{
    vector<Type>::size_type i=0;
    for(vector<Type::size_type j=2;j<vec_to_sort.size();j++)
    {
        Type key=vec_to_sort[j];
        i=j-1;
        while(i>0&&vec_to_sort[i]>
C++ 中,成员函数的声明定义分离不会导致链接错误,其根本原因在于 C++ 编译器链接器的工作机制,以及类成员函数在编译过程中的处理方式。 ### 类成员函数的分离机制 C++ 中允许将类的声明放在头文件(.h 或 .hpp)中,而将成员函数的具体实现放在源文件(.cpp)中。这种分离方式不会导致链接错误,是因为类的成员函数本质上是与类本身绑定的,其定义在编译时被单独处理。只要在使用类的成员函数时,编译器能够找到其定义所在的源文件并正确编译,链接器就能在最终链接阶段找到对应的函数符号。 例如,考虑以下类声明定义分离: ```cpp // MyClass.h class MyClass { public: void foo(); // 声明 }; ``` ```cpp // MyClass.cpp #include "MyClass.h" #include <iostream> void MyClass::foo() { // 定义 std::cout << "foo called" << std::endl; } ``` 在这种情况下,当其他源文件包含 `MyClass.h` 并调用 `MyClass::foo()` 时,编译器会生成对该函数的外部引用。只要 `MyClass.cpp` 被编译并生成相应的目标文件(.obj 或 .o),链接器就能找到该函数的地址并完成链接。 ### 编译与链接的协同工作 C++ 编译过程分为多个阶段:预处理、编译、汇编链接。在编译阶段,每个 `.cpp` 文件被独立编译为目标文件。如果某个类成员函数的定义在某个 `.cpp` 文件中存在,并且该文件被正确编译,那么该函数的符号会被记录在对应的目标文件中。在链接阶段,链接器会解析所有符号引用,并确保它们指向正确的定义。 因此,只要类成员函数的定义存在于某个源文件中,并且该文件被编译并参与最终链接,就不会出现链接错误。这与普通函数的声明定义分离机制一致。 ### 模板函数与普通成员函数的区别 与普通成员函数不同的是,模板函数的实例化发生在编译阶段,而非链接阶段。模板函数的定义必须在使用它的翻译单元中可见,否则编译器无法生成对应的实例化代码,从而导致链接错误。例如: ```cpp // Test.h template <typename T> class A { public: void f(); }; // Test.cpp template <typename T> void A<T>::f() { // 实现 } // main.cpp #include "Test.h" int main() { A<int> a; a.f(); // 编译器无法在此处实例化 f(),因为定义不可见 return 0; } ``` 在这种情况下,由于 `Test.cpp` 中没有调用 `A<int>::f()`,编译器不会为其生成实例化代码,导致链接失败。而普通成员函数没有这个问题,因为它们的定义不需要在每个使用它的翻译单元中重复出现。 ### 编译器优化与静态类型检查 C++ 的静态类型系统分离式编译机制确保了在编译阶段就能发现大多数符号未定义的问题。只要类成员函数的定义在某个 `.cpp` 文件中存在,并且该文件被正确编译,链接器就能找到其符号并完成链接。这与模板函数的延迟实例化机制形成鲜明对比。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值