自学内容网 自学内容网

5.1.1 C++函数模板和类模板注意事项

一)函数注意事项
·1.自动类型推导,必须推导出一致的数据类型T,才可以用。
·2.模板必须要确定出T的数据类型,才可以使用。(必须给出类型表达式)
二)普通函数与函数模板的区别
·1.普通函数调用时可以发生自动类型转换(隐式类型转换)。
·2.1函数模板调用时,如果利用“自动类型推导”,不会发生隐式类型转换。
·2.2函数模板调用时,如果利用“显示指定类型”的方式,可以发生隐式类型转换。
三)函数调用规则如下
·1.如果函数模板和普通函数都可以实现,优先调用普通函数。
·2.可以通过空模板参数列表来强制调用函数模板。
·3.函数模板也可以发生重载。
·4.如果函数模板可以产生更好的匹配,优先调用函数模板。
(例如当普通函数为int类型,当给定参数不是int类型,此时调用函数模板)

#include<iostream>
using namespace std;
#include<string>
void  myprint(int a, int b)//1.普通函数
{
cout<<"普通函数"<<endl;
}
template<class T> //1.函数模板
void myprint(T a, T b)
{
cout << "函数模板" << endl;
}
template<class T>
void myprint(T a, T b,T c)
{
cout << "函数重载的模板" << endl;
}
void test()
{
int a = 10;
int b = 20;
int c = 10;
myprint(a, b);
//2.通过空模板调用模板函数
myprint<>(a, b);
//3.模板函数重载调用
myprint(a, b,c);
//4.如果函数模板产生更好的匹配,优先调用函数模板
char a1 = 'a';
char b1 = 'b';
myprint(a1, b1);
}
int main()
{
test();
system("pause");
return 0;
}

学习模板可以在STL中能够运用系统提供的模板。
四)类模板
1)类模板与函数模板区别主要有两点
·1.类模板没有自动类型推导的使用方式。
·2.类模板在模板参数列表中可以有默认参数。

#include<iostream>
using namespace std;
#include<string>
//template<class typeName,class typeage>//1. 类模板不能用自动推导类型使用
template<class typeName, class typeage=int>//2.模板中有默认参数
class person
{
public:
person(typeName name,typeage age)
{
this->m_age = age;
this->m_name = name;
}
typeName m_name;
typeage m_age;
};
void test()
{
//1.类模板不能用自动推导类型使用
//person p("张三", 20);
//person<string, int>p1("张三", 19);//只能用显示指定类型
//cout << p1.m_name << p1.m_age << endl;
//2.类模板在模板参数列表中可以有默认参数
person<string>p1("张三", 19);
cout << p1.m_name << p1.m_age << endl;
}
int main()
{
test();
system("pause");
return 0;
}

2)类模板中成员函数和普通类中成员函数创建时机是有区别的
·1.普通类中的成员函数一开始就可以创建。
·2.类模板中的成员函数在调用时才创建。

#include<iostream>
using namespace std;
#include<string>
class person1//类1
{
public:
void showperson1()
{
cout << "showperson1" << endl;
}
};
class person2//类2
{
public:
void showperson2()
{
cout << "showperson2" << endl;
}
};
template<class T>//创建类模板
class myclass
{
public:
T obj;
void func1()
{
obj.showperson1();
}
void func2()
{
obj.showperson2();
}
};
void test()
{
myclass<person2>m; //调用类模板中函数,类模板中成员函数,并不是一开始就创建的,而是在模板调用时才生成
//m.func1();//类型为person1时才调用
m.func2();//类型为person2时才调用
}
int main()
{
test();
system("pause");
return 0;
}

3)当类模板碰到继承时,需要注意以下几点
·1.当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型。
·2.如果不指定,编译器无法给子类分配内存。
·3.如果想灵活指定出父类中T的类型,子类也需变为类模板。
4)类模板成员函数类外实现

#include<iostream>
using namespace std;
#include<string>
template<class T1,class T2>
class person
{
public:
person(T1 name, T2 age);
void print();
T1 m_name;
T2 m_age;
};
//构造函数类外实现
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>::print()
{
cout << "姓名:" << this->m_name << "年龄:" << this->m_age << endl;
}
void test()
{
person<string, int> p("y", 19);
p.print();
}
int main()
{
test();
system("pause");
return 0;
}

5)模板分文件编写
1,问题:类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到。
解决方法有两种
·1.直接包含.cpp源文件。
·2.将声明和实现写到同一个文件中,并更改后缀名为.hpp,hpp是约定的名称,并不是强制。

//#include "person.cpp"//第一种方式,直接包含源文件
//1.hpp文件
#pragma once
#include<iostream>
using namespace std;
template<class T1, class T2>
class person
{
public:
person(T1 name, T2 age);
void print();
T1 m_name;
T2 m_age;
};
//1.cpp文件
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>::print()
{
cout << "姓名:" << this->m_name << "年龄:" << this->m_age << endl;
}
//1.调用程序
#include <iostream>
using namespace std;
#include"person.cpp"//类模版成员函数是在调用时才生成。所以调用创建文件。
void test()
{
person<string,int> p("孙悟空",20);
p.shoeprint();
}
int main()
{
test();
system("pause");
return 0;
}

//主程序
#include<iostream>
using namespace std;
#include<string>
//第二种解决方式,将.h和.cpp的内容写在一起,改后缀名为.hpp文件。//主流方法
#include "person.hpp"
void  test()
{
person<string, int>p("张三", 19);
p.print();
}
int main()
{
test();
system("pause");
return 0;
}

6)类模板与友元
1.全局模板类内实现-直接在类内声明友元即可。
2.全局函数类外实现,需要提前让编译器知道全局函数的存在。

#include <iostream>
#include<string>
using namespace std;
//2.全局函数类外实现,提前让编译器知道person类存在
template<class T1, class T2>//提前声明person类
class person;
template<class T1, class T2>//将全局函数放到前面
void print1(person<T1, T2>p)
{
cout << "类外实现姓名:" << p.m_name << "年龄:" << p.m_age << endl;
}
template<class T1,class T2>
class person
{
//1.通过全局函数在类内实现,打印print信息
friend void print(person<T1,T2>p)//全局函数声明和实现写在一起了
{
cout << "姓名:" <<p.m_name << "年龄:" << p.m_age << endl;
}
//2.通过全局函数在类外实现,
//需要加空模板参数列表
//如果全局函数是类外实现,需要让编译器提前知道这个函数的存在
friend void print1<>(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;
};
void test()//测试1
{
person<string,int> p("张三",19);
print(p);
}
void test1()//测试2
{
person<string, int> p("张三", 19);
print1(p);
}
int main()
{
test1();
system("pause");
return 0;
 }

原文地址:https://blog.csdn.net/wgf350357114/article/details/144180928

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!