强制调用函数模板
void my_print(int a, int b)
{cout << "调用的普通函数" << endl;
}template
void my_print(T a, T b)
{cout << "调用的函数模板" << endl;
}void test02()
{int a = 10;int b = 20;// 这里通过空模板参数列表,强制调用函数模板my_print<>(a, b);
}
例如:
template
void func(T a, T b)
{a = b;
}
在上述代码中提供的赋值操作,如果传入的a和b是一个数组,就无法实现了。
因为c++为了解决这种问题,提供模板的重载,可以为这些特定的类型提供具体化的模板
template
bool my_compare(T &a, T &b)
{if (a == b){return true;}else{return false;}
}// 利用具体化Person的版本实现代码,具体化优先调用
template<> bool my_compare(Person &a, Person &b)
{if (a.m_name == b.m_name && a.m_age == b.m_age){return true;}else{return false;}
}void test03()
{Person p1("Tom", 10);Person p2("Tom", 10);bool res = my_compare(p1, p2);cout << "res = " << res << endl;
}
类模板与函数模板区别
#include
#include
// 类模板
// 类模板在模板参数列表中可以有默认参数
template
class Person
{
public:Person(NameType name, AgeType age){m_name = name;m_age = age;}void show_info(){cout << "name: " << this->m_name << endl;cout << "age: " << this->m_age << endl;}NameType m_name;AgeType m_age;
};void test03()
{// 这种写法是错误的, 类模板无法自动类型推导// Person p1("张三", 23);Person p1("张三", 23);Person p2("李四", 24)p1.show_info();
}
有三种传递方式
实际开发中,最常用的还是第一种
// 类模板
template
class Person
{
public:Person(NameType name, AgeType age){m_name = name;m_age = age;}void show_info(){cout << "name: " << this->m_name << endl;cout << "age: " << this->m_age << endl;}NameType m_name;AgeType m_age;
};// 1. 指定传入类型
void print_person(Person &p)
{p.show_info();
}// 2. 参数模板化
template
void print_person2(Person &p)
{p.show_info();
}// 3. 整个类模板化
template
void print_person3(T &p)
{p.show_info();cout << "T = " << typeid(T).name() << endl;
}void test03()
{Person p1("张三", 23);print_person(p1);Person p2("李四", 25);print_person2(p2);Person p3("王五", 18);print_person3(p3);
}
// 类内声明, 类外实现
template
class Person
{
public:Person(NameType name, AgeType age);void show_info();NameType m_name;AgeType m_age;
};template
Person::Person(NameType name, AgeType age)
{this->m_name = name;this->m_age = age;
}template
void Person::show_info()
{cout << "name: " << this->m_name << endl;cout << "age: " << this->m_age << endl;
}void test02()
{Person p1("张三", 23);p1.show_info();
}
问题:
类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到
解决:
解决方式1:直接包含.cpp源文件
解决方式2:将声明和实现写到同一个文件里,并更改后缀名为.hpp
,hpp是约定的名称,不是强制
一般使用解决方式2
person.hpp中代码:
#pragma once
#include
#include using namespace std;template
class Person
{
public:Person(NameType name, AgeType age);void show_info();NameType m_name;AgeType m_age;
};template
Person::Person(NameType name, AgeType age)
{this->m_name = name;this->m_age = age;
}template
void Person::show_info()
{cout << "name: " << this->m_name << endl;cout << "age: " << this->m_age << endl;
}
建议:全局函数在类内实现
person.hpp代码:
#pragma once
#include
#include using namespace std;template
class Person;template
void print_info2(Person p)
{cout << "类外实现-----" << p.m_name << " " << p.m_age << endl;
}template
class Person
{// 全局函数,类内实现friend void print_info(Person p){cout << "name: " << p.m_name << " " << "age: " << p.m_age << endl;}// 全局函数,类外实现// 加空模板参数列表, 表示这是一个函数模板的函数声明(这点很重要)// 如果全局函数是类外实现,需要让编译器提前知道这个函数的存在friend void print_info2<>(Person p);public:Person(NameType name, AgeType age);void show_info();private:NameType m_name;AgeType m_age;
};template
Person::Person(NameType name, AgeType age)
{this->m_name = name;this->m_age = age;
}template
void Person::show_info()
{cout << "name: " << this->m_name << endl;cout << "age: " << this->m_age << endl;
}
main.cpp代码:
void test02()
{Person p1("张三", 23);// print_info2(p1);print_info(p1);
}
案例描述:
main.cpp中的代码:
#include
#include #include "custom_array.hpp"using namespace std;class Person
{
public:// 空实现不写会报错Person() {}Person(string name, int age){this->m_name = name;this->m_age = age;}string m_name;int m_age;
};void print_arr(CustomArray& arr)
{for (int i = 0; i < arr.get_size(); i++){cout << arr[i] << "\t";}cout << endl;
}void print_person_arr(CustomArray& arr)
{for (int i = 0; i < arr.get_size(); i++){cout << "姓名:" << arr[i].m_name << "\t年龄:" << arr[i].m_age << endl;}
}void test01()
{CustomArray arr(10);// // 拷贝构造调用
// CustomArray arr2(arr);
//
// CustomArray arr3(100);
// arr3 = arr2;for (int i = 0; i < 5; i++){arr.push_back(i);}cout << "输出为:" << endl;print_arr(arr);cout << "arr的容量: " << arr.get_capacity() << endl;cout << "arr的大小: " << arr.get_size() << endl;CustomArray arr2(arr);arr2.pop_back();cout << "arr2输出为:" << endl;print_arr(arr2);cout << "arr2的容量: " << arr2.get_capacity() << endl;cout << "arr2的大小: " << arr2.get_size() << endl;
}void test02()
{CustomArray arr(10);Person p1("张三", 23);Person p2("李四", 35);Person p3("王五", 24);Person p4("赵六", 23);Person p5("钱七", 25);Person p6("孙八", 45);Person p7("周九", 30);arr.push_back(p1);arr.push_back(p2);arr.push_back(p3);arr.push_back(p4);arr.push_back(p4);arr.push_back(p6);arr.push_back(p7);print_person_arr(arr);
}int main() {
// test01();test02();system("pause");return 0;
}
custom_array.hpp中的代码:
#pragma once
#include
#include using namespace std;template
class CustomArray
{
public:// 有参构造CustomArray(int capacity){this->m_capacity = capacity;this->m_size = 0;this->p_address = new T[this->m_capacity];}// 拷贝构造CustomArray(const CustomArray& arr){this->m_capacity = arr.m_capacity;this->m_size = arr.m_size;// 浅拷贝会导致堆区数据重复释放// this->p_address = arr.p_address;// 所以要深拷贝this->p_address = new T[this->m_capacity];// 将arr中原先的数据都拷贝过来for(int i = 0; i < this->m_size; i++){this->p_address[i] = arr.p_address[i];}}// operator=CustomArray& operator=(const CustomArray& arr){// 先判断原来堆区是否有数据,如果有先释放if (this->p_address != nullptr){delete[] this->p_address;this->p_address = nullptr;this->m_capacity = 0;this->m_size = 0;}// 深拷贝this->m_capacity = arr.m_capacity;this->m_size = arr.m_size;this->p_address = new T[this->m_capacity];return *this;}// 尾插法void push_back(const T& val){// 判断容量是否已满if (this->m_capacity == this->m_size){cout << "容量已满,无法添加" << endl;return;}this->p_address[this->m_size] = val; // 在数组末尾插入数据this->m_size++;}// 尾删法void pop_back(){// 让用户访问不到最后一个元素即可(逻辑上的删除)if (this->m_size == 0){return;}this->m_size--;}// 通过下标的方式访问数组(重载[])T& operator[](int idx){return this->p_address[idx];}// 返回数组的容量int get_capacity(){return this->m_capacity;}// 返回数组的大小int get_size(){return this->m_size;}~CustomArray(){if (this->p_address != nullptr){delete[] this->p_address;this->p_address = nullptr;}}private:T* p_address; // 指向堆区开辟的真实数组int m_capacity; // 数组容量int m_size; // 数组大小
};
上一篇:FUNIT