Common uses of C++ class templates and attention to implementation

class template definition

template<class T1, class T2 > //Template parameters can have one or more
class class names {};

The difference between class templates and function templates

1. Class templates cannot be automatically type deduced, and the specified type needs to be displayed; function templates can be automatically type deduced;

2. Class templates can have default parameters in the template parameter list; default parameters cannot be used in function templates

#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;
}

When to Create a Class Template Member Function

Member functions in class templates are only created when they are called; but member functions in ordinary classes can be created from the beginning;

Verify with code

#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;
}

class template as function parameter

There are three ways to implement class templates as function parameters as follows:

1. Specify the incoming type

//The class template is sent as a function parameter in three ways

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

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

}

2, parameter template

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

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

3. The entire class is templated

//3, the entire class is templated, using the class as a template,

template<typename T>
void printStudent3(T& s) {//Note that the variable is a reference data type
    s.show();
}

void test3() {

        Student s("Xiao Ming", 3);

        printStudent3(s);

}

This source file is as follows: the commonly used one is still the first one, which is more intuitive, easy to understand, and the code is readable;

#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;
}

The class template is the most function parameter, and the way to call this function is the same;

class template inheritance

#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;
}

Member functions of class templates, implemented outside the class

See the code and comments for specific explanations, very detailed

#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;
}

Class templates are written in separate files

The member function of the template function of the class is written in separate files, that is, the declaration part is written in the header file of Animal.h; the specific code is as follows:

New header file Animal.h

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

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

The code in the Animal.cpp source file is as follows:

#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 class

Test.cpp

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

    return 1;
}

The second method of writing class template files is to write the function declaration and implementation in the .hpp file; the .hpp file and the header file are put together, which is an agreed file format is not fixed; the details are as follows

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;
}

The Animal.hpp file can be directly introduced into the Test.cpp file;

Class templates and friends

It is more convenient for the global function to be implemented in the friend class; but if it is implemented outside the class, the compiler needs to know the friend function first

#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;
}

The focus of this article is in the code, and there are many comments, so as not to understand;

Guess you like

Origin blog.csdn.net/ezconn/article/details/129468318