C++类模板常见用途和注意实现

Posted Ang_qq_252390816

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++类模板常见用途和注意实现相关的知识,希望对你有一定的参考价值。

类模板定义

template<class T1,class T2 > //模板参数可以有一个或者多个
class 类名 ;

类模板和函数模板的区别

1,类模板不能自动类型推导,需要显示的指定类型;函数模板可以自动类型推导;

2,类模板在模板参数列表中可以有默认参数;函数模板中不能使用默认参数

#include<iostream>
using namespace std;

//类模板
template<class T1,class T2>
class Student 

public :
    T1 name;
    T2 age;

    Student(T1 name, T2 age) 
        this->name = name;
        this->age = age;
    

    void show()
    
        cout << name << age << "岁了"<<endl;
    
;

//类模板中的模板参数列表可以指定默认参数.例如为模板参数T2设置默认参数int
template<class T1, class T2 =int>
class Student2 

public:
    T1 name;
    T2 age;

    Student2(T1 name, T2 age) 
    
        this->name = name;
        this->age = age;
    

    void show()
    
        cout << name << age << "岁了" << endl;
    
;


void test1() 
    Student<string, int> s("王阳明", 100);//类模板必须显示的指定模板类型,不会隐式转换;
    s.show();


void test2() //类模板中模板参数列表中设置了默认参数,使用类模板时不用再指定参数类型
    Student2<string> s("韩非子", 1001);
    s.show();


int main() 
    test1();
    test2();
    system("pause");
    return 1;

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

类模板中的成员函数只有在调用的时候才会创建;但是普通类中的成员函数一开始就可以创建;

使用代码验证

#include<iostream>
using namespace std;

class Student1 
public:
    void showMsg1() 
        cout << "我是Student1" << endl;
    
;

class Student2 
public:
    void showMsg2() 
        cout << "我是Student2" << endl;
    
;

template<class T>
class  Test 

public:
    T obj;
    void showS1() 
        obj.showMsg1();
    

    void showS2() 
        obj.showMsg2();
    
;

int main() 
    Test<Student1> t;//如果不调用Test中的成员函数,可以编译通过,也就是验证了,类模板成员函数是在调用时创建;不调用不创建;

    t.showS1(); //到这里程序也能运行起来
        //t.showS2(); //如果调用成员函数showS2()就要报错,因为Student1中没有成员函数showS2();如果不调用showS2()程序就没问题,进一步说明类模板的成员函数再调用时才创建;
    return 1;

类模板作为函数参数

类模板最为函数参数有三种实现方式如下:

1,指定传入类型

//类模板最为函数参数三种方式发

//1,指定传入类型,指明类模板中模板参数具体类型;
void printStudent1(Student& s) //注意变量为引用数据类型
      s.show();


//类模板作为参数的函数调用
void test1() 
    Student s("小米", 4);
    printStudent1(s);

2,参数模板化

//2,参数模板化,把类模板中模板参数模板化,不指定具体类型;其实就是函数模板加类模板的结合使用
template<typename T1,typename T2>
void printStudent2(Student<T1, T2>&s) //注意变量为引用数据类型
    s.show();


void test2() 
    Student<string, int > s("小艾", 5);
    printStudent2(s);

3,整个类模板化

//3,整个类模板化,把类作为一个模板,

template<typename T>
void printStudent3(T& s) //注意变量为引用数据类型
    s.show();

void test3()

        Student s("小明", 3);

        printStudent3(s);

这个源文件如下:常用的还是第一种,比较直观,容易理解代码可读性强;

#include<iostream>
using namespace std;

template <typename T1,typename T2>
class Student

public :
    string name;
    int age;
    Student(T1 t1, T2 t2) 
        this->name = t1;
        this->age = t2;
    

    void show() 
        cout << name << "同学今年" << age << "岁" << endl;
    
;

//类模板最为函数参数三种方式发
//1,指定传入类型,指明类模板中模板参数具体类型;
void printStudent1(Student<string, int>& s) //注意变量为引用数据类型
    s.show();


//类模板作为参数的函数调用
void test1() 

    Student<string, int > s("小米", 4);
        printStudent1(s);


//2,参数模板化,把类模板中模板参数模板化,不指定具体类型;其实就是函数模板加类模板的结合使用
template<typename T1,typename T2>
void printStudent2(Student<T1, T2>&s) //注意变量为引用数据类型
    s.show();


void test2() 
    Student<string, int > s("小艾", 5);
    printStudent2(s);



//3,整个类模板化,把类作为一个模板,
template<typename T>
void printStudent3(T& s) //注意变量为引用数据类型
    s.show();


void test3() 
    Student<string, int > s("小明", 3);
    printStudent3(s);


int main()

    test1();
    test2();
    test3();

    return 1;

类模板最为函数参数,调用这个函数的方式都一样;

类模板继承

#include<iostream>
using namespace std;

template<class T>
class Animal 
public:
    T type;

    Animal() 
        cout << "T的类型:" << typeid(T).name() << endl;
    
;

//类模板中的继承,需要制定父类模板参数的具体类型;语法规定
class Dog :public Animal<int> 


;

//不指定具体类型也可以,把子类也变为类模板,传模板参数到父类;这样在子类中也可以动态的指定父类的模板参数类型,可变的;具体如下
template<class T1,class T2>
class Cat :public Animal<T2> 

public:
    T1 name;
    void show() //可以通过系统函数typeid()查看以下父类的T和子类的T1函数调用时传入的具体类型
        cout << "T1的类型:" << typeid(T1).name() << endl;
        cout << "T2的类型:" << typeid(T2).name() << endl;
        //cout << "T的类型:" << typeid(T).name() << endl; //注意T是父类的模板参数,这里不能判断是其类型,不然会报T未声明;
    
;

int main() 
    Cat<string, int> cat;
    cat.show();

    return 1;

类模板的成员函数,类外实现

具体解释看代码及注释,很详细

#include<iostream>
using namespace std;

template<class T>
class Animal 
public:
    T name;

    Animal(T name);
    /*
        cout << "T的类型:" << typeid(T).name() << endl;
    */

    void show();//成员函数声明
    /*
        cout << "动物名字:" << name << endl;
    */
;
//成员函数类外实现:1,复制成员函数的声明;2,去掉“;”加上 3,添加作用域(Animal::);


template<typename T>//标识为模板
Animal<T>::Animal(T name)//<T>用于区分和其他模板函数的不同

    this->name = name;

template<typename T>
void Animal<T>::show() // Animal<T>后面的<T>用于标识为类模板的成员函数;
    cout << "动物名字叫:" << name << endl;




int main() 
    Animal<string> a("小狗钱钱");
    a.show();

    return 1;

类模板分文件编写

类的模板函数的成员函数类外实现的分文件编写,即把声明部分写道Animal.h的头文件中;具体代码如下:

新建头文件Animal.h

#pragma once
#include<iostream>
using namespace std;
 
template<class T>
class Animal 
public:
    T name;

     Animal(T name);
     void show();//成员函数声明
;

Animal.cpp源文件中代码如下:

#include "Animal.h" //引入自定义的文件名使用""号

//成员函数类外实现:1,复制成员函数的声明;2,去掉“;”加上 3,添加作用域(Animal::);
template<typename T>//标识为模板
Animal<T>::Animal(T name)//<T>用于区分和其他模板函数的不同

    this->name = name;

template<typename T>
void Animal<T>::show() // Animal<T>后面的<T>用于标识为类模板的成员函数;
    cout << "动物名字叫:" << name << endl;

测试类

Test.cpp

#include "Animal.cpp" //注意是导入的.cpp文件也就是源码文件,一般不会这样写,不然相当于把源码暴露给别人了;
int main() 
    Animal<string> a("小狗钱钱");
    a.show();

    return 1;

类模板的分文件编写第二种方法,把函数声明和实现都写在.hpp文件中;.hpp文件和头文件放在一起,是约定的一个文件格式不是固定的;具体如下

Animal.hpp

#include<iostream>
using namespace std;

template<class T>
class Animal 
public:
    T name;
    Animal(T name);
    void show();//成员函数声明
;


//成员函数类外实现:1,复制成员函数的声明;2,去掉“;”加上 3,添加作用域(Animal::);

template<typename T>//标识为模板
Animal<T>::Animal(T name)//<T>用于区分和其他模板函数的不同

    this->name = name;


template<typename T>
void Animal<T>::show() // Animal<T>后面的<T>用于标识为类模板的成员函数;
    cout << "动物名字叫:" << name << endl;

Test.cpp文件中直接引入Animal.hpp文件即可调用;

类模板和友元

全局函数做友元类内实现,比较方便;但是如果类外实现需要先让编译器知道友元函数

#include<iostream>
using namespace std;

template<typename T1, class T2>
class Student;

//全局函数做友元,类外实现
template<class T1,class T2>
void showStudent2(Student<T1, T2> s)//这里用到Student类所以再次函数之前要先声明;

    s.print();//友元函数可以访问类中的私有成员方法和成员属性


template<typename T1,class T2>
class Student 
    //全局函数做友元,类内实现
    friend void showStudent(Student<string, int> s) //可以把模板参数列表换成T1,T2;
    
        s.print();//友元函数可以访问类中的私有成员方法和成员属性
    


    //全局函数做友元,类外实现 ,需要注意类外实现首先要告诉编译器,所以要在Student类之前实现showStudent2函数
    friend void showStudent2<>(Student<T1, T2> s);//注意需要加空模板参数列表<>

private:
    T1 name;
    T2 age;

    void print() 
        cout << "这位学生叫" << name << age << "岁了" << endl;
    

public:
    Student(T1 name, T2 age) 
        this->name = name;
        this->age = age;
    
;



int main() 
    Student<string,int> s("小度", 5);
    showStudent(s);

    Student<string, int> s2("小宝", 3);
    showStudent2(s2);
    return 1;

本文重点都在代码里面,注释很多,以免看不懂;

以上是关于C++类模板常见用途和注意实现的主要内容,如果未能解决你的问题,请参考以下文章

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

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

C+JavaPython选择哪个编程语言?

一个Go和C++多用途工程项目的模型研究

一个Go和C++多用途工程项目的模型研究

一个Go和C++多用途工程项目的模型研究