1.自动推导类型
在C语言和C++98中,auto 关键字用于修饰变量(自动存储的局部变量)。
在C++11中,赋予了auto 全新的含义,不再用于修饰的变量,而是作为一个类型指示符,指示编译器在编译时推导auto声明的变量的数据类型。
在Linux 平台下,编译需要加-std=c++11 参数。
#include <iostream>
using namespace std;
// 如果初始化变量的时候不定义类型,那么会使用auto关键字
// 根据变量赋值,自动推导出相关类型
int main() {
auto a = 3; cout << "a=" << a << endl;
auto b = 3.3; cout << "b=" << b << endl;
auto c = "鲁班"; cout << "c =" << c << endl;
system("Pause");
}
注意事项:
- auto声明的变量必须在定义时初始化
- 初始化的右值可以是具体的数值,也可以是表达式和函数的返回值等
- auto不能作为函数的形参类型
- auto不能直接声明数组
- auto不能定义类的非静态成员变量
auto关键字的真正用途:
- 代替冗长复杂的变量声明
- 在模板中,用于声明依赖模板参数的变量。
- 函数模板依赖模板参数的返回值
- 用于lambda 表达式中
auto关键字可以计算两个不同类型的值
#include <iostream>
using namespace std;
template<typename T1, typename T2>
void func(T1 x, T2 y) {
auto tmp = x + y;
cout << tmp << endl;
}
int main() {
short a = 1;
char b = 2;
func(a, b);
system("Pause");
return 0;
}
2.函数模板
先看一段代码:如果我们需要更换两个变量的值,根据变量值的不同,需要不断的重载Swap函数,函数中的tmp变量类型也会改变,其他地方都一样。
#include <iostream>
using namespace std;
// 交换两int值
void Swap(int &a ,int &b) {
int tmp = a;
b = a;
a = tmp;
}
// 交换两double值
void Swap(double& a, double& b) {
double tmp = a;
b = a;
a = tmp;
}
// 交换两字符串值
void Swap(string& a, string& b) {
string tmp = a;
b = a;
a = tmp;
}
int mian() {
}
为了避免这种麻烦,利用模型来生成相应的函数代码,即函数模板:
- 函数模板是通用的函数描述,使用任意类型(泛型)来描述函数
- 编译的时候,编译器推导实参的数据类型,根据实参的数据类型和函数模板,生成该类型的函数定义
- 生成函数定义的过程被称为实例化。
创建交换两个变量的函数模板:
#include <iostream>
using namespace std;
// 创建一个函数模板,交换两个变量的值
// 定义模板,这里anytype可以随便取名,但是需要注意和下面一致
// 函数模板用typename 类模板用 class
template <typename T>
void Swap(T& a, T& b) {
T tmp = a;
a = b;
b = tmp;
}
int main() {
int a = 1, b = 2;
cout << a << b << endl;
Swap(a, b);
cout << a << b << endl;
system("Pause");
return 0;
}
注意事项:
- 可以为类的成员函数创建模板,但不能是虚函数和析构函数
- 使用函数模板时,必须明确数据类型,确保实参与函数模板能匹配上
- 使用函数模板时,推导的数据类型必须适应函数模板中的代码
- 使用函数模板时,如果是自动类型推导,不会发生隐式类型转换,如果显式指定了函数模板的数据类型,可以发生隐式类型转换
- 函数模板支持多个通用数据类型的参数
#include <iostream>
using namespace std;
class Fruit {
public:
// 构造函数
template <typename T>
Fruit(T a) {
cout << "a=" << a << endl;
}
// 用到模板的地方在上面都要加这一句
template <typename T1,typename T2>
void show(T1 b,T2 c) {
cout << "b=" << b << endl;
cout << "c=" << c << endl;
}
};
int main() {
Fruit apple("烟台红苹果");
apple.show("真的甜","好吃");
system("Pause");
return 0;
}
函数模板的具体化
语法:
template<>void 函数模板名<数据类型>(参数列表)
template<>void 函数模板名(参数列表)
{
// 函数体
}
#include <iostream>
using namespace std;
class Fruit {
public:
// 构造函数
Fruit(const string& f_name,int f_gram) {
m_gram = f_gram;
m_name = f_name;
}
void show_gram() {
cout << this->m_name << this->m_gram << endl;
}
string m_name;
int m_gram;
};
// 函数模板
template<typename T>
void Swap(T& a, T& b) {
T tmp = a;
a = b;
b = tmp;
cout << "调用了Swap(T& a, T&b)" << endl;
}
//具体化函数
template<>void Swap(Fruit& f1, Fruit& f2) {
int tmp = f1.m_gram;
f1.m_gram = f2.m_gram;
f2.m_gram = tmp;
cout << "调用了Swap(Fruit& f1, Fruit& f2)" << endl;
}
int main() {
Fruit apple("苹果", 12), orange("橘子", 55);
apple.show_gram();
orange.show_gram();
Swap(apple, orange);
apple.show_gram();
orange.show_gram();
system("Pause");
return 0;
}
- 具体化优先于常规模板,普通函数优先于具体化
- 如果希望使用函数模板,可以用空模板参数强制使用函数模板
- 如何函数模板能产生更好的匹配,将优先于非函数模板
声明和定义分开
函数模板的定义和声明都是在头文件中,普通函数和函数模板的具体化版本是分开的。
main.cpp
#include <iostream>
#include"public.h"
using namespace std;
int main() {
Swap(1, 1); // 使用普通函数
Swap('c', 'd'); // 使用函数模板
Swap<>(1, 1); // 使用函数模板具体化版本
system("Pause");
return 0;
}
头文件public.h:
#pragma once
#include <iostream>
using namespace std;
void Swap(int a, int b); // 普通函数
template<typename T> // 函数模板
void Swap(T a, T b) {
cout << "使用了函数模板" << endl;
}
template<>
void Swap(int a, int b); // 函数模板具体化版本
源文件public.cpp
#include "public.h"
void Swap(int a, int b) {
cout << "使用了普通函数" << endl;
}
template<>
void Swap(int a, int b) {
cout << "使用了具体化的函数模板" << endl;
}
3.类模板
template <class T>
class 类模板名
{
类的定义
}
#include <iostream>
using namespace std;
template<class T1,class T2>
class AA {
public:
T1 m_a;
T2 m_b;
AA(T1 a, T2 b) :m_a(a), m_b(b){}
//构造函数
AA() {}
// 可以用于成员函数的返回值
// 即a是什么类型,这里geta返回的也是什么类型
T1 geta() {
T1 num = 2; // 这里也可以定义一个和a相同类型的与a相加
return m_a + num;
}
T2 getb() {
T1 num = 2;
return m_b;
}
};
int main() {
AA<int, double>a; // 用模板类AA创建对象
a.m_a = 2;
a.m_b = 3;
cout << "a.geta()=" << a.geta() << endl;
cout << "a.getb()=" << a.getb() << endl;
system("Pause");
return 0;
}
可以用new创建模板类对象:main函数这么写
int main() {
AA<int, double>*a=new AA<int, double>(1,2); // 用模板类AA创建对象
cout << "a.geta()=" << a->geta() << endl;
cout << "a.getb()=" << a->geta() << endl;
delete a;
system("Pause");
return 0;
}
类模板的具体化
#include <iostream>
using namespace std;
//类模板
template<class T1,class T2>
class AA {
T1 mx;
T2 my;
AA(const T1 x, const T2 y) :mx(x), my(y) { cout << "类模板,构造函数" << endl; }
void show()const;//类内声明,类外实现
};
// 成员函数类外实现
template<class T1,class T2>
void AA<T1, T2>::show()const {
cout << "类模板:x=" << mx << ",y=" << my << endl;
};
//类模板完全具体化
template<>class AA<int, string> {
public:
int mx;
string my;
AA(const int x, const string y) :mx(x), my(y) { cout << "完全具体化:构造函数" << endl; };
void show()const;
};
void AA<int, string>::show()const {
cout << "完全具体化x=" << mx << ",y=" << my << endl;
};
//类模板部分显示具体化
template<class T1>
class AA<T1, string> { // T1通用,string具体
public:
T1 mx;
string my;
AA(T1 x, const string y) :mx(x), my(y) { cout << "部分具体化:构造函数 " << endl; };
void show()const {
cout << "部分具体化x=" << mx << ",y=" << my << endl;
};
};
int main() {
//具体化程度高的类优先于具体化程度低的类,具体化的类优先于没有具体化的类
AA<int, string>aa(22, "光头强");
aa.show();
system("Pause");
return 0;
}
类模板的继承
-
模板类继承普通类(常见)
-
普通类继承模板类的实例版本
-
普通类继承模板类(常见)
-
模板类继承模板类
-
模板类继承模板参数给出的基类(不能是模板类)
下面演示第一种:模板类继承普通类
#include <iostream>
using namespace std;
class AA { // 普通类AA
public:
int m_a;
AA(int a) :m_a(a) { cout << "调用AA构造函数" << endl; }
void func1() { cout << "调用func1函数:m_a=" << m_a << endl; }
};
template<class T1,class T2>
class BB:public AA // 模板类BB
{
public:
T1 m_x;
T2 m_y;
BB(const T1 x, const T2 y,int a):AA(a),m_x(x), m_y(y) { cout << "调用BB构造函数" << endl; }
void func2() { cout << "调用func2函数,x+y=" << m_x <<",m_y=" << m_y << endl; }
};
int main() {
BB<int, string>bb(22, "光头强", 6666);
bb.func1();
cout << "--------------------" << endl;
bb.func2();
system("Pause");
return 0;
}
第三种情况:普通类继承模板类:
#include <iostream>
using namespace std;
template<class T1,class T2>
class BB // 模板类BB
{
public:
T1 m_x;
T2 m_y;
BB(const T1 x, const T2 y):m_x(x), m_y(y) { cout << "调用BB构造函数" << endl; }
void func2() { cout << "调用func2函数,x+y=" << m_x <<",m_y=" << m_y << endl; }
};
template<class T1, class T2>
class AA:public BB<T1,T2> { // 普通类AA
public:
int m_a;
AA(int a,const T1 x,const T2 y) :BB<T1,T2>(x,y),m_a(a) { cout << "调用AA构造函数" << endl; }
void func1() { cout << "调用func1函数:m_a=" << m_a << endl; }
};
int main() {
AA<int, string>aa(1,22, "光头强");
aa.func1();
cout << "--------------------" << endl;
aa.func2();
system("Pause");
return 0;
}
类模板的成员模板
#include <iostream>
using namespace std;
template<class T1,class T2>
class AA {
public:
T1 m_x;
T2 m_y;
AA(const T1 x,const T2 y):m_x(x),m_y(y){}
void show() { cout << "m_x=" << m_x << " m_y=" << m_y << endl; }
template<class T> // 类模板
class BB
{
public:
T m_a;
T1 m_b;
BB(){}
void show() { cout << "m_a=" << m_a << " m_b=" << m_b << endl; }
};
BB<string>bb; // bb就是类模板AA的一个成员
//函数模板
template<typename TF>
void showf(TF tt) { cout << "tt=" << tt << endl; }
};
int main() {
AA<int, string>a(22, "光头强");
a.show();
a.bb.m_a = "熊大";
a.bb.show();
a.showf("看我大卫天龙");
system("pause");
return 0;
}