C++函数&类模板

函数模板基本语法

ini 复制代码
void swapInt(int &a, int &b){
    int temp = a;
    a = b;
    b = temp;
}
​
void swapDouble(Double &a, Double &b){
    Double temp = a;
    a = b;
    b = temp;
}
//定义模板 T通用数据类型
template<typename T>
​
void swapNum(T &a, T &b){
    T temp = a;
    a = b;
    b = temp;
}
​
test01(){
    //call template method
    //1,Automatic type derivation
    int a = 1;
    int b = 2;
    swapNum(a, b);
    //2,Display specified type
    swapNum<int>(a, b);
}

函数模板注意事项

template 中typename可以被替换为class。

template定义模板类型后紧随其后的是使用该模板的函数。该函数必须包含T类型的形参列表 。对于自动类型推导,传参必须能够推导出一致的数据类型T才可以使用。

ini 复制代码
template<typename M>

void swap(M& a, M& b) {
	M temp = a;
	a = b;
	b = temp;
}

void func() {
	std::cout << "this is a func" << std::endl;
}

void test(){
	int a = 10;
	int b = 20;
	swap(a, b);
	func();
}

排序函数模板化

std::sort 能够实现自动推导类型 的原因是因为它是一个 模板函数 ,并且 C++ 使用了 模板类型推导(Template Type Deduction) 机制。模板函数允许根据传入的参数类型自动推导出函数模板的具体类型,这使得 std::sort 能够适应不同类型的容器和元素,而无需显式指定模板参数。

普通函数与模板函数的区别

普通函数模板函数的指定类型推导可以进行隐式类型转换,模板函数的自动类型推导则不行。

css 复制代码
int myadd01(int a, int b){
    return a+b;
}

template<typename T>
T myadd02(T a,T b){
    return a+b;
}

void test(){
    int a = 1;
    int b = 2;
    char c = 'c';
    myadd01 (a , b);
    myadd01 (a , c);
    myadd02(a,b);
    (x)myadd02(a,c);
    myadd02<int>(a,c);
}

函数模板的调用规则

1,普通函数和函数模板都能实现的情况下,优先调用普通函数

2,可以通过指定空模板类型推导,强行调用函数模板

3,函数模板也可以发生重载

4,如果函数模板可以产生容易匹配(不需要隐式转换),则会优先调用函数模板,例如在4演示代码中,调用普通函数需要进行隐式转换,而直接传参与模板匹配可以避免发生转换

c 复制代码
void myPrint(int a, int b) {
	cout << "Call Normal Func";
}

template <typename C>
void myPrint(C a, C b) {
	cout << "Call template";
}

template <typename C>
void myPrint(C a, C b, C c) {
	cout << "Call template overload";
}

void test0001() {
	int a = 10;
	int b = 10;
	//1
	myPrint(a, b);
	cout << endl;
	//2
	myPrint<>(a, b);
	cout << endl;
	//3
	int c = 10;
	myPrint(a, b, c);
	cout << endl;
	//4
	char c1 = 'c';
	char c2 = 'd';
	myPrint(c1, c2);
}

int main() {
	test0001();
}

函数模板局限性

函数模板并非万能,在处理一些自定义数据类型的操作时,我们需要具体化模板。

例如进行类对象之间的比较时,我们或者进行类内运算符重载,或者进行模板具体化,否则不能正常进行比较。

csharp 复制代码
Overload is calling
not
Overload is calling
equel
test Match ================
Specific is calling
equel
    
class Person {
public:
	int age;
	string name;

	Person(int age, string name) {
		this->age = age;
		this->name = name;
	}

	bool operator==(Person &p1) {
		cout << "Overload is calling" << endl;
		if (this->age == p1.age && this->name == p1.name) {
			return true;
		}
		else {
			return false;
		}
	}
};

template <typename T>
bool match(T &p1, T &p2) {
	if (p1 == p2) {
		return true;
	}
	else {
		return false;
	}
}

template<> bool match(Person &p1, Person &p2) {
	cout << "Specific is calling" << endl;

	if (p1.age == p2.age && p1.name == p2.name) {
		return true;
	}
	else {
		return false;
	}
}


void result(bool res) {
	if (res) {
		cout << "equel";
	}
	else {
		cout << "not";
	}
	cout << endl;
}

void testL() {
	Person Tom(13, "Tom");
	Person Tom2(13, "Tom");
	Person Amy(14, "Amy");
	bool res = (Tom == Amy);
	result(res);
	bool res2 = (Tom == Tom2);
	result(res2);
	cout << "test Match ================" << endl;
	bool res3 = match(Tom, Tom2);
	result(res3);
}

类模板基本语法&类模板与函数模板的区别

csharp 复制代码
template<class nameT,class ageT>
class person1{
    public:
    nameT p1Name;
    ageT p1Age;
    person(nameT name,ageT age){
    this->p1Name = name;
    this->p1Age = age;
    }
    
    void showP1(){
        cout<<"p1"<<endl;
    }
};
​
int main(){
    (x)person1 p1("Nick", 99);
    person1<string, int> p1("Nick", 99);
}

类模板无法使用自动类型推导

类模板中成员函数的创建时机

类模板成员函数,在调用时才创建

csharp 复制代码
class p1{
    public:
    void showp1(){
        cout<<"p1"<<endl;
    }
};
class p2{
    public:
    void showp2(){
        cout<<"p2"<<endl;
    }
};
template<class T>
class test{
    public:
    void p1show(){
        T.showp1();
    }
    void p2show(){
        T.showp2();
    }
};
//在完成上面的代码后并不会报错,因为还无法确定T的具体类型
int main(){
    test<p1> obj;
    obj.p1show();
    obj.p2show();
};

类模板对象做函数参数

1,指定传入类型法(√)

其他方法实际上都需要类模板结合函数模板使用

2,参数模板化法

3,类模板化法

csharp 复制代码
template<class NameType, class AgeType = int>
class Person{
public:
    Person(NameType name, AgeType age){
        this->mName = name;
        this->mAge = age;
    }
    void showPerson(){
        cout<<"name: "<<this->mName<<"age: "<<this->age<<endl;
    }
    public:
    NameType mName;
    AgeType mAge;
};
​
//assign put in type for template
void printAssign(Person<string, int> &p){
    p.showPerson();
}
void test01(){
    Person<string, int>p{"Pa", 10};
    printAssign(p);
}
​
//Parameter templating
template<class T1, class T2>
void printParatemplate(Person<T1, T2>&p){
    p.showPerson();
    cout<<"T1类型: "<<typeid(T1).name() <<endl;
    cout<<"T2类型: "<<typeid(T2).name() <<endl;
}
​
void test02(){
    Person <string, int>p("Pb", 20);
    printParatemplate(p);
}
​
//entire class is templating
template<class T>
void printClasstemplate(T &p){
    cout<<"T的类型: "<<typeid(T).name()<<endl;
    p.showPerson();
}
​
void test03(){
    Person<string, int>p("Pc", 30);
    printClasstemplate(p);
}
​
int main(){
    test01();
    test02();
    test03();
}
​

类模板与继承

子类继承父类模板,必须显式指定模板实际类型,如果想要保持灵活性,子类也必须为类模板。

arduino 复制代码
template<class T>
class Base{
    T m;
};
//class son : public Base语法报错,c++编译器需要给子类分配内存,没有明确的类型无法完成
class son : public Base<int>{
};
​
void test01(){
    Son c;
}
​
//子类模板继承父类模板,可以用T2指定父类T的类型!
template<class T1, class T2>
class Son2 : public Base<T2>{
public:
    Son2(){
        cout<<typeid(T1).name()<<endl;
        cout<<typeid(T1).name()<<endl;
    }    
};
​
test02(){
    Son2<int, char> child;
}
​

类模板成员函数类外实现

类模板

kotlin 复制代码
template<class T1, class T2>
class Person {
public:
    T1 m_Name;
    T2 m_Age;
​
    Person(T1 name, T2 age);
    void showPerson();
};
​
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age) {
    this->m_Name = name;
    this->m_Age = age;
}
​
template<class T1, class T2>
void Person<T1, T2>::showPerson() {
    cout << "姓名: " << this->m_Name << "年龄: " << this->m_Age << endl;
}

类模板分文件编写

解决分文件编写时链接不到的问题。

person.h

ruby 复制代码
template<class T1, class T2>
class Person{
    T1 mName;
    T2 mAge;
    Person(T1 mName, T2 mAge);
    show();
};

person.cpp

arduino 复制代码
#include "person.h"

template<class T1, class T2>
Person<T1,T2>::Person(T1 name, T2 age){
    this->mName = name;
    this->mAge = age;
}

template<class T1, class T2>
void Person<T1, T2>::show(){
    cout<<"..."<<endl;
}

main.cpp

c 复制代码
(x)#include "person.h"
//error can't find corresponding func, generate in call
(√)#include "person.cpp"
//或者将.h .cpp 文件合并为.hpp文件,在main中包含
void test(){
    Person<string, int>p("j", 18);
    p.show();
}

类模板与友元

类模板友元函数的类内/外实现

arduino 复制代码
template<class T1, class T2>class Person;
​
template<class T1, class T2>void showPerson2(Person<T1, T2>) {
    cout << "out of class姓名: " << this->m_Name << "年龄: " << this->m_Age << endl;
}
​
template<class T1, class T2>class Person {
    friend void showPerson(Person<T1, T2>& p) {
        cout << "in class姓名: " << this->m_Name << "年龄: " << this->m_Age << endl;
    }
​
    friend void showPerson2<>(Person<T1, T2>& p);
    
public:
    Person(T1 name, T2 age) {
        this->m_Name = name;
        this->m_Age = age;
    }
​
private:
    T1 m_Name;
    T2 m_Age;
};

项目:数组类封装

kotlin 复制代码
#pragma once
#include<iostream>
​
using namespace std;
​
template<class T>
class MyArray {
private:
    T* arrAd;
    int arrCap;
    int arrSiz;
public:
    MyArray(int capa) {
        this->arrCap = capa;
        this->arrSiz = 0;
        this->arrAd = new T[this->arrCap];
    }
​
    //copy
    MyArray(const MyArray& arr) {
        this->arrCap = arr.arrCap;
        this->arrSiz = arr.arrSiz;
        //this->arrAd = arr.arrAd;
        this->arrAd = new T[arr.arrCap];
​
        for (int i = 0; i < this->arrSiz; i++) {
            this->arrAd[i] = arr.arrAd[i];
        }
    }
​
    //operator=如果想要返回值作为左值使用,需要返回引用
    MyArray& operator=(const MyArray& arr) {
        
        if (this->arrAd != NULL) {
            delete[] this->arrAd;
            this->arrAd = NULL;
            this->arrCap = 0;
            this->arrSiz = 0;
        }
​
        this->arrCap = arr.arrCap;
        this->arrSiz = arr.arrSiz;
        this->arrAd = new T[arr.arrCap];
​
        for (int i = 0; i < this->arrSiz; i++) {
            this->arrAd[i] = arr.arrAd[i];
        }
​
        return *this;
    }
​
    void push_back(const T& val) {
        if (this->arrCap == this->arrSiz) {
            return;
        }
        this->arrAd[this->arrSiz] = val;
        this->arrSiz++;
    }
    
    void pop_back() {
        if (this->arrSiz == 0) {
            return;
        }
        this->arrSiz--;
    }
​
    T& operator[](int index) {
        return this->arrAd[index];
    }
​
    int getCap() {
        return this->arrCap;
    }
​
    int getSiz() {
        return this->arrSiz;
    }
​
    ~MyArray() {
        if (this->arrAd != NULL) {
            delete[] this->arrAd;
        }
    }
};
相关推荐
明月看潮生7 分钟前
青少年编程与数学 02-018 C++数据结构与算法 16课题、贪心算法
c++·算法·青少年编程·贪心算法·编程与数学
Wooden-Flute1 小时前
十一、引用与拷贝函数(References & the Copy-Constructor)
c++
fpcc2 小时前
跟我学C++中级篇——控制死锁
c++·软件工程
wjm0410062 小时前
C++日更八股--first
java·开发语言·c++
RanceGru3 小时前
C++——调用OpenCV和NVIDIA Video Codec SDK库实现使用GPU硬解码MP4视频文件
c++·opencv·算法·gpu算力·视频编解码
点云SLAM3 小时前
C++ 中自主内存管理 new/delete 与 malloc/free 完全详解
c++·算法·指针·内存管理·new/delete·malloc/free·内存地址
爱凤的小光4 小时前
图漾官网Sample_V1版本C++语言完整参考例子---单相机版本
开发语言·c++·数码相机
青瓦梦滋4 小时前
【语法】C++的继承
开发语言·c++
ttk2195 小时前
【算法练习】归并排序和归并分治
数据结构·c++·算法·排序算法
mooridy5 小时前
设计模式 | 详解常用设计模式(六大设计原则,单例模式,工厂模式,建造者模式,代理模式)
c++·设计模式