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

  • 普通函数调用时可以发生自动类型转换(隐式类型转换)
  • 函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
  • 如果利用显示指炭类型的方式,可以发生隐式类型转换

示例:

#include<iostream>
using namespace std;

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

//1.普通函数调用可以发生隐式类型转换
//2.函数模板 用自动类型推导,不可以发生隐式类型转换
//3.函数模板 用显式指定类型,可以发生隐式类型转换

//普通函数
int myAdd01(int a, int b)
{
    return a + b;
}


//函数模板
template<class T>
T myAdd02(T a,T b)
{
    return a + b;
}

void test01()
{
    int a =10;
    int b = 20;
    char c ='c'; // a- 97 c -99
    cout<<myAdd01(a,c)<< endl;

    //自动类型推导不会发生隐式类型转换
    //cout<<myAdd02(a,c)<<endl;

    //显示指定类型会发生隐式类型转换
    cout<<myAdd02<int>(a,c)<<endl;

}

int main()
{
    test01();
    system("pause");
    return 0;
}

总结:建议使用显示指定类型的方式,调用函数模板,因为可以自己确定通用类型T

1.2.5普通函数与函数模板的调用规则


调用规则如下:
1.如果函数模板和普通函数都可以实现,优先调用普通函数
2.可以通过空模板参数列表来强制调用函数模板
3.函数模板也可以发生重载
4.如果函数模板可以产生更好的匹配,优先调用函数模板


示例:

#include<iostream>
using namespace std;


//普通函数与函数模板调用规则
//1、如果函数模板和普通函数都可以调用,优先调用普通函数
//2、可以通过空模板参数列表强制调用函数模板
//3、函数模板可以发生函数重载
//4、如果函数模板可以产生更好的匹配,优先调用函数模板

void myPrint (int a, int b);
{
    cout<<"调用的普通函数"<<endl;
}

template<class T>
evoid myPrint(T a,T b)
{
    cout<<"调用的模板"<< endl;
}

template<class T>
evoid myPrint(T a,T b,T c)
{
    cout<<"调用的重载的模板"<< endl;
}


void testo1()
{
    int a =10;
    int b = 20;

    //myPrint(a,b);

    //通过空模板参数列表,强制调用函数模板
    //myPrint<>(a,b);

    //myPrint (a, b, 100);

    //如果函数模板产生更好的匹配,优先调用函数模板
    char c1 ='a';
    char c2 ='b';
    myPrint(c1, c2);
}

int main()
{

    test01();    

    system("pause");
    return 0;
}

总结:既然提供了函数模板,最好就不要提供普通函数,否则容易出现二义性

1.2.6模板的局限性

局限性:

  • 模板的通用性并不是万能的

例如:

template<class T>
void f(T a, T b)
{
   а=b;
}

在上述代码中提供的赋值操作,如果传入的a和b是一个数组,就无法实现了。


再例如:

template<class T>
void f(T a, T b)
{
    if(a > b) { ....}
}

在上述代码中,如果T的数据类型传入的是像Person这样的自定义数据类型,也无法正常运行


因此C++为了解决这种问题,提供模板的重载,可以为这些特定的类型提供具体化的模板


示例:

#include<iostream>
using namespace std;
#include <string>

//模板局限性
//模板并不是万能的,有些特定数据类型,需要用具体化方式做特殊实现

class Person
{
public:

    Person(string name, int age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }
    
    //姓名
    string m_Name;
    //年龄
    int m_Age;

}

//对比两个数据是否相等函数
template<class T>
bool myCompare(T &a, T &b)
{
    if (a == b)
    {
        return true;
    }
    else
    {
        return false;
    }
}


//利用具体化Person的版本实现代码,具体化优先调用
template<> bool myCompare(Person &p1,Person &p2)
{
    if(pl.m_Name == p2.m_Name && pl.m_Age == p2.m_Age)
    {
        return true;
    }
    else
    {
        return false;
    }

void test01()
{
    int a =10;
    int b = 20;
    bool ret = myCompare(a, b);

    if(ret)
    {
        cout << "a == b" << endl;
    }
    else
    {
        cout << "a != b" << endl;
    }
}




void test02()
{
    Person p1("Tom",10);
    Person p2("Tom",10);

    bool ret = myCompare(pl, p2);
    if (ret)
    {
        cout<<"pl == p2" << endl;
    }
    else
    {
        cout << "pl != p2" << endl;
    }
}

int main()
{
    test01();

    test02();

    system("pause");
    return 0;
}

总结:

  • 利用具体化的模板,可以解决自定义类型的通用化
  • 学习模板并不是为了写模板,而是在STL能够运用系统提供的模板

1.3 类模板
1.3.1 类模板语法
类模板作用:

  • 建立一个通用类,类中的成员数据类型可以不具体制定,用一个虚拟的类型来代表。

语法:
template<typename T>

解释:
template ---- 声明创建模板
typename ---- 表面其后面的符号是一种数据类型,可以用class代替
T ------ 通用的数据类型,名称可以替换,通常为大写字母
示例:

#include<iostream>
using namespace std;
#include<string>

//类模板
template<class NameType, class AgeType>
class Person
{
public:
    Person (NameType name,AgeType age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }

    void showPerson()
    {
        cout<<"name:"<<this->m_Name <<"age:"<<this->m_Age << endl;
    }

    NameType m_Name;
    AgeType m_Age;
};

void test01()
{
    Person<string,int> pl("孙悟空",999);
    pl.showPerson();
}

int main()
{
    test01();

    system("pause");

    return 0;
} 

总结:类模板和函数模板语法相似,在声明模板template后面加类,此类称为类模板。

1.3.2类模板与函数模板区别
类模板与函数模板区别主要有两点:
1.类模板没有自动类型推导的使用方式
2.类模板在模板参数列表中可以有默认参数
示例:

#include<iostream>
using namespace std;
#include<string>

//类模板与函数模板区别
template<class NameType, class AgeType = int>
class Person
{
public:
    Person (NameType name,AgeType age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }

    void showPerson()
    {
        cout<<"name:"<<this->m_Name <<"age:"<<this->m_Age << endl;
    }

    NameType m_Name;
    AgeType m_Age;
};

//1、类模板没有自动类型推导使用方式
void test01()
{
    //Personp(孙悟空”,1000);错误,无法用自动类型推导
    Person<string,int> p("孙悟空",1000);//正确,只能用显示指定类型
    p.showPerson();
}

//2、类模板在模板参数列表中可以有默认参数
void test02
{
    Person<string> p("猪八戒",999);
     p.showPerson();
}


int main() 
{
    test01();
    test02();
    system("pause");
    return 0;
}

总结:

  • 类模板使用只能用显示指定类型方式
  • 类模板中的模板参数列表可以有默认参数

1.3.3类模板中成员函数创建时机
类模板中成员函数和普通类中成员函数创建时机是有区别的:

  • 普通类中的成员函数一开始就可以创建
  • 类模板中的成员函数在调用时才创建

示例:

class Person1
{
public:
    void showPerson1()
    {
        cout<"Person1 show"<endl;
    }
};

class Person2
{
public:
    void showPerson2()
    {
        cout << "Person2 show" << endl;
    }
};

template<class T>
class MyClass
{
public:
    T obj;

    //类模板中的成员函数,并不是一开始就创建的,而是在模板调用时再生成
    void func1()
    {
        obj.showPerson1();
    }

    void func2()
    {
        obj.showPerson2();
    }
};
    
void teste1()
{
    MyClass<Person1> m;
    m.fun1();
    //m.fun2();//编译会出错,说明函数调用才会去创建成员函数
}

int main()
{

    test01();
    system("pause");
    return 0;
}

总结:类模板中的成员函数并不是一开始就创建的,在调用时才去创建。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐