C++ 模板

函数模板

函数模板,是可以创建一个通用的函数,可以支持多种形参。

用关键字 template 来定义,

在函数模板中,数据的值和类型都被参数化了,发生函数调用时编译器会根据传入的实参来推演形参的值和类型。

template 
返回值 函数名(形参表列) 模板参数表
{
    // 函数体
}

第一行的template是一句声明语句

template 是定义模板函数的关键字

尖括号里可以有多个类型

用class(或者typename来定义)。

然后后面跟定义的函数模板,切记中间不可以加其他的语句,不然会报错!

#include 
#include 
using namespace std;

template 
void print(T);

int main()
{
    print(55);
    print('Y');
    print("Hello");
    system("pause");
    return 0;
}

template 
void print(T x)
{
    cout
        << x
        << endl;
}

函数模板也可以提前声明,不过声明时需要带上模板头,并且模板头和函数定义(声明)是一个不可分割的整体,它们可以换行,但中间不能有分号。

类模板

的定义格式:

template class 类名{
    //TODO:
};

例:

template
class Student 
{
    // 成员变量  成员函数
};

在类外定义成员函数时仍然需要带上模板头

成员函数定义模板格式:

template
返回值类型 类名<类型参数1 , 类型参数2, ...>::函数名(形参列表){
    //TODO:
}

例:

template
void Student::say(){
};

构造函数 以及 析构函数 的模板 ,两者类似,析构函数只需要 多添加一个 ~ 符,且没有参数

template
类名<类型参数1 , 类型参数2, ...>::类名(形参列表) : 变量初始化{
    //TODO:
}

例:

// 构造函数
template
Student::Student(T1 a, T2 b) :m_a(a), m_b(b) {};

// 析构函数
template
Student::~Student() {
};

指针对象 注意事项:

  • 赋值号两边的数据类型必须一致
  • 赋值号右边需要指明数据类型
格式:
类名<类型参数1,类型参数2 ····> 对象名 = new 类名<类型参数1,类型参数2 ····>(初始化参数1,参数2 ·····);

例:
Student *Man = new Student("浑元形意太极门掌门人", "马保国");
#include 
#include 

using namespace std;
template
class Student 
{
private:
    T1 m_a;
    T2 m_b;
public:
    Student(T1 a, T2 b);
    void say();
    ~Student();
};
// 构造函数
template
Student::Student(T1 a, T2 b) :m_a(a), m_b(b) {};
// 成员函数
template
void Student::say(){
    cout << this->m_a << this->m_b << endl;
};
// 析构函数
template
Student::~Student() {
    cout << this->m_a << this->m_b << endl;
};

int main()
{
    Student Sir("浑元形意太极门掌门人","马保国");
    Sir.say();
    Student c(2,'B');
    c.say();
    Student *Man = new Student("练习两年半的偶像练习生", "坤坤");
    Man->say();
    delete Man;

    return 0;
}

结果:
浑元形意太极门掌门人马保国
2B
练习两年半的偶像练习生坤坤
练习两年半的偶像练习生坤坤
2B
浑元形意太极门掌门人马保国

类模板的静态成员

静态模板成员变量

static 数据类型 变量名;

初始化格式:
template
数据类型 类名<类型参数1 , 类型参数2, ...>::变量名 = 数据;

注意: 数据类型定义与初始化要一致

不使用模板定义静态变量:

static T1 count1;

// 模板静态成员变量初始化  
template
T1 Student::count1 = 0;

使用固定类型定义静态变量:

static int count2;

// 模板静态成员变量初始化
template
int Student::count2 = 0;

注意:

  • 静态成员变量,可以在类的内部使用,可以在外部进行操作

  • 静态成员变量使用模板定义时,当传入的模板类型不是可以操作的类型就会报错

原本希望传入的是整型,然后进行++操作

结果传入了string类型,由于不匹配所以会出现以下错误提示:

错误  C2676   二进制“++”:“T1”不定义该运算符或到预定义运算符可接收的类型的转换
#include 
#include 

using namespace std;

template
class Student
{
public:
    static T1 count;    // 计数
private:
    T1 m_a;
    T2 m_b;
public:
    Student(T1 a, T2 b);
    void say();
};

// 构造函数
template
Student::Student(T1 a, T2 b) :m_a(a), m_b(b) {
    //count++; //传入的类型T1 不为整数可操作类型,就会报错, C2676
};

// 成员函数
template
void Student::say() {
    cout  << ". " << this->m_a << this->m_b << endl;
    
    // 静态成员变量初始化之后,在类中使用时,会引发异常  此位置的异常 : return (_CSTD strlen(_First));
    //cout << this->count << endl;
};

template
T1 Student::count = 0;// 仅初始化,不在类中使用,就不会出现问题,但也就好无意义了

int main()
{
    Student Sir("浑元形意太极门掌门人", "马保国");
    // 因为传入了string类型,count可以手动赋值来计数,但无法通过,会引发异常, 此位置的异常 : return (_CSTD strlen(_First));
    // Sir.count = "1";
    Sir.say();
    return 0;
}

引起一系列问题的原因可能为:

1. 设置的类型初始化问题
    不能匹配确定是否合理初始化
    
2. 设置类型与想要操作的类型不匹配
    希望使用 ++等一些列运算符 操作的 整数或浮点数类型
    时间类型为 string

传入类型合理类型,修改上例的相关区域:

// 构造函数
template
Student::Student(T1 a, T2 b) :m_a(a), m_b(b) {
    count++; 
};
// 成员函数
template
void Student::say() {
    cout << ". " << this->m_a << this->m_b << endl;
    cout << this->count << endl;
};

// 初始化
template
T1 Student::count = 0;


// 创建对象
Student Sir(2,"B" );
Sir.count++;
Sir.say();


结果:
. 2B
2

因此解决此类问题,就可以为static类型变量,创建 特定的构造函数 以及 模板

#include 
#include 

using namespace std;

// T3专门用来给静态变量传递模板数据类型
template
class Student
{
public:
    static T3 count;   // 计数
private:
    T1 m_a;
    T2 m_b;
public:
    Student(T1 a, T2 b);
    void say();
};

// 构造函数,可以设置空的构造函数,之后通过接口传值,此处就省略
template
Student::Student(T1 a, T2 b) :m_a(a), m_b(b) {
    count++;
};
// 成员函数
template
void Student::say() {
    cout << this->count  << ". " << this->m_a << this->m_b << endl;
};

// 静态成员变量的初始化
template
T3 Student::count = 0;

int main()
{
    Student Sir("浑元形意太极门掌门人", "马保国");
    Sir.say();

    Student *Man = new Student("练习两年半的偶像练习生", "坤坤");
    Man->say();
    delete Man;

    Student c(2, 'B');
    c.say();    
    Student l(3, 'B');
    l.say();    
    Student s(6, 'B');
    s.say();
    return 0;
}

结果:
1-1. 浑元形意太极门掌门人马保国
2-2. 练习两年半的偶像练习生坤坤
1-1. 2B
2-2. 3B
3-3. 6B
  • 通过静态变量可以知道,每次类的模板不同,就会产生新的类,且不互通

上例产生了两个类的格式

  • Student
  • Student

类模板与友元函数

// 模板类
template
class Student
{
private:
    T m_x;
    T m_y;
public:
// 构造函数
    Student(T x, T y) :m_x(x), m_y(y) {};
// 友元函数
    friend T sum(Student s);
};

// 函数模板
template
T sum(Student s)
{
    return s.m_x + s.m_y;
}

严重性 代码  说明  项目  文件  行   禁止显示状态
错误  LNK2019 无法解析的外部符号 "class std::basic_string,class std::allocator > __cdecl sum(class Student,class std::allocator > >)" (?sum@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@V?$Student@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@@@Z),该符号在函数 "void __cdecl Study(void)" (?Study@@YAXXZ) 中被引用 学习  E:\C++\学习\学习\Study.obj  1   

类模板 不能 引入函数模板,虽然程序没有错误,但是在编译时就会出错

友元函数 需要指明 具体的参数类型 ,可以通过 重载 去定义多个 友元函数

注意: 友元函数 无法直接 访问类模板的参数,需要传递 类的对象对象指针

#include 
#include 

using namespace std;

// 模板类
template
class Student
{
private:
    T m_x;
    T m_y;
public:
// 构造函数
    Student(T x, T y) :m_x(x), m_y(y) {};
// 友元函数的声明
    friend string sum(Student s);
    friend int sum(Student s);
};

// 友元函数的定义
string sum(Student s)
{
    return s.m_x + s.m_y;
}
int sum(Student s)
{
    return s.m_x + s.m_y;
}

int main()
{
    Student Sir("浑圆形意太极门掌门人", "马保国");
    cout << sum(Sir) << endl;
    
    Student Age(6,9);
    cout << sum(Age) << endl;
    return 0;
}

类模板与 友元 类的成员函数

friend 表示 出现 friend 的类

member 表示 成员函数的类

定义的一般顺序:

第一步:
class friend;

第二步:
template 
class member{
    // 成员变量 , 成员函数
    // 需要 友元的成员函数 声明
}

第三步:
class friend{
    // 成员变量 , 成员函数
    // friend member类的 友元成员函数
}

第四步:
member类的 友元成员函数 的实现

例子:

#include 
#include 

using namespace std;

template
class Student;      // 同样很有必要的声明


// 第一个类, member类
class Introduct
{
public:
    // 成员函数
    string sum(Student* s); // 对象指针
    int sum(Student s);        // 对象
};

// 第二个类,友元类
template
class Student
{
private:
    T m_x;
    T m_y;
public:
// 构造函数
    Student(T x, T y) :m_x(x), m_y(y) {};
// 友元函数的声明
    friend string Introduct::sum(Student* s);
    friend int Introduct::sum(Student s);
};


// 友元函数的定义
string Introduct::sum(Student* s)
{
    return s->m_x + s->m_y;
}
int Introduct::sum(Student s)
{
    return s.m_x + s.m_y;
}


int main()
{
    Introduct Mk;

    Student Sir("浑圆形意太极门掌门人", "马保国");
    cout << Mk.sum(&Sir) << endl;

    Student Age(6,9);
    cout << Mk.sum(Age) << endl;
    return 0;
}

结果:
浑圆形意太极门掌门人马保国
15

通过 重载 来扩展, member类的使用

同样需要传递 实例对象 或 实例对象指针,访问类的成员

类模板与 友元 模板类的成员函数

两个类模板之间

  1. 提前声明 member类
  2. 定义 friend类, 引入友元的成员函数
  3. 定义 member类
  4. 定义 模板成员函数
#include 
#include 

using namespace std;

template
class Introduct;        // 有必要的提前定义

// 第一个类, 友元类
template
class Student
{
private:
    T m_x;
    T m_y;
public:
    Student(T x, T y) :m_x(x), m_y(y) {};
    // 友元类
    friend T Introduct::sum(Student s);
};


// 第二个类, member类
template
class Introduct
{
public:
    // 成员函数
    S sum(Student s);
};

// 模板成员函数
template
S Introduct::sum(Student s)
{
    return s.m_x + s.m_y;
}

int main()
{
    Introduct Mk;
    Student Sir("浑圆形意太极门掌门人", "马保国");
    cout << Mk.sum(Sir) << endl;

    Introduct M;
    Student Age(6, 9);
    cout << M.sum(Age) << endl;
    return 0;
}

注意:
在使用模板时,前后要对应

类模板 与 友元 类

优先定义 友元类

#include 
#include 

using namespace std;

// 第一个类, 友元类
template
class Student
{
private:
    T m_x;
    T m_y;
public:
    Student(T x, T y) :m_x(x), m_y(y) {};
    // 友元类
    friend class Introduct;
};


// 第二个类, member类
class Introduct
{
public:
    // 成员函数
    string sum(Student* s); // 对象指针
    int sum(Student s);        // 对象
};

// Introduct成员函数
string Introduct::sum(Student* s)
{
    return s->m_x + s->m_y;
}
int Introduct::sum(Student s)
{
    return s.m_x + s.m_y;
}

int main()
{
    
    Introduct Mk;

    Student Sir("浑圆形意太极门掌门人", "马保国");
    cout << Mk.sum(&Sir) << endl;

    Student Age(6,9);
    cout << Mk.sum(Age) << endl;
    return 0;
}

结果:
浑圆形意太极门掌门人马保国
15

类模板 与 友元类类模板与 类的友元成员函数 类似,不同点就是前者无需过多声明 成员函数,后者需要依次 声明 需要用到的 成员函数

类模板 与 友元 类模板

两个 类模板

  1. 提前声明 member类
  2. 定义 friend类 , 引入 友元类
  3. 定义 member类
  4. 定义 模板成员函数
#include 
#include 

using namespace std;

template
class Introduct;        // 很有必要的声明

// 第一个类, 友元类
template
class Student
{
private:
    T m_x;
    T m_y;
public:
    Student(T x, T y) :m_x(x), m_y(y) {};
    // 友元类
    friend class Introduct;
};


// 第二个类, member类
template
class Introduct
{
public:
    // 成员函数
    S sum(Student s);
};

template
S Introduct::sum(Student s)
{
    return s.m_x + s.m_y;
}


int main()
{
    
    Introduct Mk;
    Student Sir("浑圆形意太极门掌门人", "马保国");
    cout << Mk.sum(Sir) << endl;

    Introduct M;
    Student Age(6, 9);
    cout << M.sum(Age) << endl;
    
    return 0;
}

结果:
浑圆形意太极门掌门人马保国
15

类模板与非类型参数

在定义模板的时候,可以引入参数

不能使用 结构体string 等定义非类型参数

template 

例如:
template 
class Student
{
}

在传递参数时,需要传递相对应的数据类型的数据
Student Sir;

例如:

#include 
#include 

using namespace std;

// 模板类
template
class Student
{
private:
    T m_n;
public:
    // 构造函数
    Student(T n) :m_n(n){};
    T say()
    {
        m_n += count;
        return m_n;
    }
};

// 

void Study()
{
    Student Sir(1);
    cout << Sir.say() << endl;
    cout << Sir.say() << endl;
    cout << Sir.say() << endl;
    cout << Sir.say() << endl;
}

结果:
3
5
7
9

类模板的继承

基类模板 与 子类

#include 
#include 

using namespace std;

// 基类
template 
class People
{
public:
    T m_num;
public:
    // 构造函数
    People(T num) : m_num(num) {};
    // 成员变量
    void show()
    {
        cout << "num = " << this->m_num << endl;
    }
};

// 子类
class Student : public People {
private:
    int m_code;
public:
    // 构造函数
    Student(int code, int num) :m_code(code), People(num) {};
    // 成员变量
    void show()
    {
        cout << "code = " << this->m_code << ";"
             << "num = " << this->m_num << endl;
    }
};


int main()
{
    People sir_1(10);
    sir_1.show();

    Student sir_2(996, 777);
    sir_2.show();
    
    return 0;
}

结果:
num = 10
code = 996;num = 777

基类模板 与 子类模板

#include 
#include 

using namespace std;

// 基类
template 
class People
{
public:
    T m_num;
public:
    // 构造函数
    People(T num) : m_num(num) {};
    // 成员变量
    void show()
    {
        cout << "num = " << this->m_num << endl;
    }
};

// 派生类
template 
class Student : public People {
private:
    S m_code;
public:
    // 构造函数
    Student(S code, S num) :m_code(code), People(num) {};
    // 成员变量
    void show()
    {
        cout << "code = " << this->m_code << ";"
             << "num = " << this->m_num << endl;
    }
};


int main()
{
    People sir_1(10);
    sir_1.show();

    Student sir_2(996, 777);
    sir_2.show();
    
    return 0;
}

结果:
num = 10
code = 996;num = 777

注意:构造函数,基类要指明类型,继承是也要指明类型,且前后照应

模板实参推断

从函数实参来确定模板实参的过程被称为模板实参推断(template argument deduction)

使用函数模板显示实参,可以覆盖实参推断机制

#include 
#include 

using namespace std;

template
int max(T1 a, T2 b)
{
    cout
        << "T1 = " << sizeof(T1) << endl
        << "T2 = " << sizeof(T2) << endl;
        
    if (a > b) return a;
    else if (a == b) return 0;
    else return b;
}

int main()
{
    short sh = 6;
    
    // 系统推断
    cout << max(sh, 3) << endl; 
    // 显式定义
    cout << max(sh, 3) << endl; 
    cout << max(sh, 3) << endl;
    return 0;
}

结果:
T1 = 4
T2 = 2
6
T1 = 4
T2 = 2
6
T1 = 4
T2 = 4
6

模板实例化

模板实例化是生成采用特定模板参数组合的具体类或函数(实例)

编译器生成一个采用 Array 的类,另外生成一个采用 Array 的类。通过用模板参数替换模板类定义中的模板参数,可以定义这些新的类。

隐式实例化

隐式实例化:通过编译器自己推测判断要实例化的类型。

编译器会根据实参推断类型

显式实例化

模板显式实例化(extern template)可以用来确保模板只被编译器实例化一次

  • 使用模板生成的编译单元不会重复实例化,会加快编译速度,并减小编译单元的尺寸

要显式实例化模板函数,在 template 关键字后接函数的声明(不是定义),且函数标识符后接模板参数。

template 返回值类型 函数名 <数据类型>

例如:
template
T1 max(T1 a, T2 b)
{
    if (a > b) return a;
    else if (a == b) return 0;
    else return b;
}

template int max(int a, int b);  //显式实例化,只需声明

模板类的显式实例化

template class 类名<数据类型>

例如:
template
class Student
{
private:
    T m_x;
    T m_y;
public:
    Student(T x,T y) :m_x(x), m_y(y) {};
    void prin()
    {
        cout << m_x << m_y << endl;
    }
};

// 显式实例化 类模板
template class Student;
template class Student;

模板类静态数据成员的显式实例

template 返回值类型 类名<数据类型>::函数名(参数列表);

例如:
template
class Student
{
private:
    T m_x;
    T m_y;
public:
    Student(T x,T y) :m_x(x), m_y(y) {};
    T sum(T a);
};

template
T Student::sum(T a)
{
    return this->m_x + this->m_y + a;
}

// 显式实例化 类模板
template string Student::sum(string a);
template int Student::sum(int a);

注意:类型的规范,使用相同模板在带入数据类型时,也要同步,不要随心所欲,想使用不同类型就分开定义,一句话:早知现在何必当初

模板显式具体化

让模板能够针对某种具体的类型使用不同的算法(函数体或类体不同),称为模板的显示具体化(Explicit Specialization)

利用对函数模板的显式具体化,对于 数组结构体 数据类型进行操作

C++98标准 : 原型和定义以 template<> 开头,并通过名称指出类型。函数调用优先级是 非模板函数 > 具体化模板函数 > 常规模板函数

函数模板类模板 的基础上,新添加一个专门针对 特定类型 的、实现方式不同具体化 函数或类

模板函数显式具体化

template<> 
数据类型 函数名<复杂数据类型>(参数列表){
    // 函数体
}

例如:
template 
T stripling(T a, T b)
{
    return a < b ? a : b;
};

// 只有定力了原型模板,才能定义如下的显式具体化,原型模板如上 template  T stripling(T a, T b)
// People 为定义的结构体类型
template <>
People stripling(People a, People b)
{
    return a.age < b.age ? a : b;
};
#include 
#include 

using namespace std;

typedef struct{
    string name;
    int age;
}People;

// 输出 较大值
template 
T stripling(T a, T b)
{
    return a < b ? a : b;
};

// 需要有原型,如上 template  T stripling(T a, T b)
template <>
People stripling(People a, People b)
{
    return a.age < b.age ? a : b;
};

void prin(People sir)
{
    cout << sir.name << "," << sir.age << "岁,不讲武德" << endl;
}

int main()
{
    People young1 = { "八十公斤的年轻人",35 };
    People young2 = { "九十公斤的年轻人",30 };
    People leader = { "马保国",69 };
    prin(stripling(young1,leader));
    prin(stripling(young2,leader));
    return 0;
}

模板类的显式具体化

在类模板的具体化中,成员方法的实例化是不能带模板头template<>的。

template<>
class 类名<复杂数据类型>
{
    // 成员变量
    // 成员函数
}

例如:
template 
class People {
    // 成员变量 成员函数
}

// msg 为 结构体
template<>
class People
{
    // 成员变量 成员函数
}
#include 
#include 

using namespace std;

template 
class People
{
private:
// 成员变量
    T1 m_x;
    T2 m_y;
public:
// 构造函数
    People(T1 x, T2 y) :m_x(x), m_y(y) {};
// 成员函数
    void show();
};

template 
void People::show()
{
    cout << m_x << "," << m_y << endl;
}

// 类模板显式具体化(针对 结构体 的显式具体化)
typedef struct
{
    string name;
    int age;
} msg ;

template<>
class People
{
private:
// 成员变量
    msg m_leader;
    msg m_young;
public:
// 构造函数
    People(msg leader,msg young) :m_leader(leader), m_young(young){};
// 成员函数
    void show();
};

// 注意!这里不能带模板头template<>
void People::show()
{
// 判断 年轻人 与 掌门人 年龄
    msg stripling = this->m_leader.age > this->m_young.age ? m_leader : m_young;
// 输出年龄大的老同志
    cout << stripling.name << ":" << stripling.age << endl << "马家功夫名不虚传" << endl;
}


int main()
{
    People Sir("浑圆形意太极门掌门人","马保国");
    Sir.show();

    msg young = { "八十公斤的年轻人",35 };
    msg leader = { "马保国",69 };
    People Man(leader,young);
    Man.show();
    return 0;
}

结果:
浑圆形意太极门掌门人,马保国
马保国:69
马家功夫名不虚传

部分显式具体化

部分显式具体化只能用于类模板,不能用于函数模板

template
class 类名<复杂数据类型 , 模板类型>         // 模板类型 要 对应,位置不固定,根据情况而定
{
    // 成员变量
    // 成员函数
}

例如:
template 
class People {
    // 成员变量 成员函数
}

// msg 为 结构体
template
class People
{
    // 成员变量 成员函数
}
#include 
#include 

using namespace std;

template 
class People
{
private:
// 成员变量
    T1 m_x;
    T2 m_y;
public:
// 构造函数
    People(T1 x, T2 y) :m_x(x), m_y(y) {};
// 成员函数
    void show();
};

template 
void People::show()
{
// 输出数据
    cout << m_x << "," << m_y << endl;
}

// 部分显式具体化(针对 结构体 的部分显式具体化)
typedef struct
{
    string name;
    int age;
}msg;

template
class People
{
private:
// 成员变量
    msg m_leader;
    T m_sure_age;
public:
// 构造函数
    People(msg leader,T sure_age) :m_leader(leader), m_sure_age(sure_age){};
// 成员函数
    void show();
};

// 注意!需要带模板头
template
void People::show()
{
// 修改数据,并输出
    this->m_leader.age = this->m_sure_age;
    cout << this->m_leader.name << ":" << this->m_leader.age << endl << "马家功夫名不虚传" << endl;
}


int main()
{
    People Sir("浑圆形意太极门掌门人","马保国");
    Sir.show();

    msg leader = { "马保国",35 };
    People Man(leader,69);
    Man.show();
    
    return 0;
}

结果:
浑圆形意太极门掌门人,马保国
马保国:69
马家功夫名不虚传

模板 用于多文件编程

在将函数用于多文件编程时,我们通常是将 函数定义 放在 源文件(.cpp 文件) 中,将 函数声明 放在 头文件(.h文件)中,使用函数时 引入(#include 命令) 对应的 头文件 即可

编译是针对单个源文件的,只要有函数声明,编译器就能知道函数调用是否正确;而将函数调用和函数定义对应起来的过程,可以延迟到链接时期。正是有了连接器的存在,函数声明和函数定义的分离才得以实现。

模板并不是真正的函数或类,它仅仅是用来生成函数或类的一张 “图纸”,在这个生成过程中有三点需要明确:

  • 模板的实例化是按需进行的,用到哪个类型就生成针对哪个类型的函数或类,不会提前生成过多的代码
  • 模板的实例化是由编译器完成的,而不是由链接器完成的
  • 在实例化过程中需要知道模板的所有细节,包含声明和定义(只有一个声明是不够的,可能会在链接阶段才发现错误)

头文件:s.h ,存放类模板的定义

#ifndef s
#define s

template
class Student
{
private:
    T m_x;
    T m_y;
public:
    Student(T x, T y) :m_x(x), m_y(y) {};
    T sum();
};

#endif

cpp文件,定义类的成员函数

#include 
#include 
#include "s.h"

using namespace std;

template
T Student::sum()
{
    return this->m_x + this->m_y ;
}

main函数调用

#include "s.h"
#include 
#include 
using namespace std;
int main()
{
    Student Sir(1, 3);
    cout << Sir.sum() << endl;

    system("pause");
    return 0;
}

直接就报错

严重性 代码  说明  项目  文件  行   禁止显示状态
错误  LNK2019 无法解析的外部符号 "public: int __thiscall Student::sum(void)" (?sum@?$Student@H@@QAEHXZ),该符号在函数 _main 中被引用 学习  E:\C++\学习\学习\学习.obj 1   

错误  LNK1120 1 个无法解析的外部命令    学习  E:\C++\学习\Debug\学习.exe  1   

但如果将 类的成员函数 定义放到 头文件:s.h ,这些错误就没有了

不能将模板的声明和定义分散到多个文件中的根本原因是:模板的实例化是由编译器完成的,而不是由链接器完成的,这可能会导致在链接期间找不到对应的模板实例。

参考:

  1. 将 C++ 模板应用于多文件编程

由于参考内容过多,在这里就不一一列举,如若有问题,请联系我,会及时修改,添加!!!

你可能感兴趣的:(C++ 模板)