首页 > 编程语言 >C++模板(函数模板 & 类模板)

C++模板(函数模板 & 类模板)

时间:2022-08-19 19:02:30浏览次数:70  
标签:调用 函数 int void C++ 模板 cout

模板编程可称范型编程,是一种忽视数据类型的编程方式,这样的好处是什么?且看下面一个例子:

简单使用

求解最值问题,返回两个值中的较大值:

int Max(int a, int b)
{
	return a>b?a:b;
}
double Max(int a, int b)
{
	return a>b?a:b;
}
string Max(string a,string b)
{
	return a>b?a:b;
}

使用Max函数处理数据类型不同的变量时,不得不重复写相同函数体的函数,于是引入了模板编程,可将类型当作未知量,使用template <typename type>来修饰函数:

template <typename type> 
type Max(type a, type b)
{
    return a>b?a:b;
}

或者

template <class T>
void print(T data)
{
	cout << data << endl;
}

这两种声明方法是等价的

调用方法分为隐式调用和显式调用

在main函数中隐式调用:

int main(void)
{
    cout << Max(1, 2) << endl;
    cout << Max(1.1,2.2) << endl;
    cout << Max(string("ILoveYou"),string("IMissYou")) << endl;
    return 0;
}

输出:

2
2.2
IMissYou

显式调用,使用<>传类型的参数,也就是在<>填写上数据类型,放到参数和函数名之间

int main(void)
{
    cout << Max<int>(1, 2) << endl;
    cout << Max<float>(1.1, 2.2) << endl;
    cout << Max<string>("ILoveYou","IMissYou") << endl;
    return 0;
}

输出:

2
2.2
IMissYou

函数模板

此处着重讨论函数模板和普通函数的使用注意点

如果在代码中存在同名的普通函数和模板函数:

int Max(int a, int b)
{
    cout << "comman function..." << endl;
    return a > b? a:b;
}

template <class T>
T Max(T a, T b)
{
    cout << "function template..." << endl;
    return a > b? a:b;
}

那么使用模板的显式调用时,调用的一定是模板函数,隐式调用时,优先调用类型确定的函数

int main(void)
{
    cout << Max<int>(1, 2) << endl;
    cout << Max(1, 2) << endl;
    return 0;
}

如上所示,第一个Max调用模板函数,第二个Max调用普通函数

如果代码中存在同名的模板函数,但参数个数不同:

template <class T1, class T2, class T3>
void print(T1 one, T2 two, T3 three)
{
    cout << "three types" << endl;
}

template <class T1, class T2>
void print(T1 one, T2 two, T2 three)
{
    cout << "two types" << endl;
}

template <class T>
void print(T one, T two, T three)
{
    cout << "one type" << endl;
}

这可以理解为函数模板的重载(类型个数的不同也可以认为是重载),在显式调用情况下:

int main(void)
{
    print<int, double, string>(1, 1.1, string("AAA"));
    print<int, double>(1, 1.22, 1.1);
    print<int>(1, 2, 3);
    return 0;
}

输出:

three types
two types
one type

这里要注意的是,数据类型要和参数匹配

隐式调用略显麻烦,有时发现多个模板都能使用,常常优先调用需要传参较少的函数模板,如下所示:

int main(void)
{
    print(1, 1, 1);
    return 0;
}

输出 one type

可见类型参数最少的模板(只要传入一个类型)被调用了,但如果参数的类型各不相同,那也只能调用3个类型参数的函数模板了:

int main(void)
{
    print(1, 1.1, string("AAA"));
    return 0;
}

输出: three types

类中的方法也可以应用函数模板:

class Test
{
public:
    template <class T>
    void print(T data) {
        cout << data << endl;
    }
};

同样可以忽视数据类型,调用时通过对象调用即可

函数模板的类型参数可以缺省,这和普通函数参数的缺省是一样的规则,只能从右往左缺省

int main(void)
{
    printData<int>(1, string("Hello"));
    return 0;
}

这里类型参数就有缺省,但是因为声明了默认参数,所以就将第二个类型认为是string

函数模板还可以向类型参数中传常量:

template <class T,size_t size>
void printArray(T* array)
{
    for (int i=0;i<size;i++) {
        cout << array[i] << " ";
    }
    cout << endl;
}

int main(void)
{
    int num[3] = {1, 2, 3};
    printArray<int, 3>(num);
    return 0;
}

输出: 1 2 3

类模板

类也可以应用模板,类模板不是一个完整的类型,所以任何用到类名的地方都要用类名<未知类型>的方式使用,同时在多文件中不能分开写,定义和声明位于同一文件,可以写在.hpp文件中(声明和实现放在一起),并且类模板只支持显示调用方式

如下案例,对C++结构体使用模板:

template <class T1, class T2>
struct my_pair
{
    T1 first;
    T2 second;
};
int main(void)
{
    my_pair<int,int> pairData = {1, 2};
    cout << pairData.first << " " << pairData.second << endl;
    my_pair<int, string>* p = new my_pair<int, string>;
    p->first = 1;
    p->second = "2";
    cout << p->first << " " << p->second << endl;
    return 0;
}

输出:

1 2
1 2

如下使用类模板:

template <class type1,class type2> 
class Test
{
public:
    // constructor
    Test(type1 one,type2 two):one(one),two(two) {

    }
    void printTest();
protected:
    type1 one;
    type2 two;   
};

template <class type1,class type2> 
void Test<type1,type2>::printTest()
{
    cout << one << " " << two << endl;
}

template <class type1, class type2>
class Data :public Test<type1,type2>
{
public:
    Data(type1 one, type2 two) :Test<type1,type2>(one,two) {

    }
protected:
};

int main(void)
{
    Data<int,int> data(1,2);
    data.printTest();

    return 0;
}

上述代码中首先定义了一个使用template修饰的类模板,声明了变量、构造函数和方法,在实现类模板的方法时也必须加上template进行修饰,在声明Data类继承Test时,也必须加上template修饰,在实例化时,使用<>显式的指定出数据类型

标签:调用,函数,int,void,C++,模板,cout
From: https://www.cnblogs.com/N3ptune/p/16603056.html

相关文章

  • 【模板】杜教筛
    #include<stdio.h>#include<math.h>#include<map>#defineullunsignedlonglong#definelltlonglongint#defineuitunsignedintconstintN=5e6+10;int......
  • 跳表模板
    跳表是一种单链表的改进,在刷力扣时看到的,有篇博客写的不错,分析了跳表的复杂度和基本原理。链接搬在这里:CSND参考博客关于数据结构的定义、查询、添加和删除的操作,力扣12......
  • C++ std::transform的使用
    头文件:<algorithm>作用:std::transform在指定的范围内应用于给定的操作,并将结果存储在指定的另一个范围内  //字符串操作std::stringstr1="HelloWorld";......
  • 10 继承模板 & inclution_tag & 文章的详情页设计 & 文章点赞 & 文章的评论
    模板继承即渲染:文章点赞或反对:跟评论和子评论:settings.pysettings.pyUSE_TZ=False#转时区改为False编写url:urls.pyfromdjango.urlsimportre_pat......
  • Python基础之reduce函数
    哈喽大家好,今天说一下reduce函数的使用方法,以及与for循环的对比。reduce函数原本在python2中也是个内置函数,不过在python3中被移到functools模块中。reduce函数先从......
  • python基础-函数式编程
    概念:电脑运算视作数学上的函数计算高阶函数:map,reduce,filter无副作用,相同的参数调用时钟产生同样的结果闭包Closure例子:defcache(func):store={}#外部自由......
  • UE5中 uDraper 插件无法编译 C++ 工程的修复
    UE5中uDraper插件无法编译C++工程的修复uDraper是用来做布料模拟的插件。现在出现的问题是安装了uDraper之后无法编译C++工程。经典报错就是:Expecting to find......
  • 练习7:函数记忆相关
    何为函数记忆函数记忆是指将上次的计算结果缓存起来,当下次调用时,如果遇到相同的参数,就直接返回缓存中的数据。常用于,复杂且有重复的计算。例如:斐波那契数列的计算under......
  • @FunctionalInterface 函数式接口
    作用:在编译过程中,校验该接口只有一个抽象方法;解释:除了唯一的抽象方法外,可以包含已经有实现的方法(包括静态方法);使用:可以使用Lambda表达式来表示该接口的一个实现:@Functi......
  • Python中,函数的返回值
    deffun(num):odd=[]#存奇数even=[]#存偶数foriinnum:ifi%2:odd.append(i)else:even.append(i)re......