当前位置:网站首页>Function template_ Class template

Function template_ Class template

2022-06-25 07:40:00 Who can keep company for a long time

Why function templates

Project requirements : Implement multiple functions to return the maximum value of two numbers , Requirements can support char type 、int type 、double Type variable

// demo 15-2.c
#include <iostream>
using namespace std;

int Max(int a, int b)
{
    
	return a>b ? a:b;
}

char Max(char a, char b)
{
    
	return a>b ? a:b;
}

float Max(float a, float b)
{
    
	return a>b ? a:b;
}

void main()
{
    
	//char a = 'c';
	
	int  x = 1;
	int	 y = 2;
	cout<<"max(1, 2) = "<<Max(x, y)<<endl; 

	float a = 2.0;
	float b = 3.0;
  
	cout<<"max(2.0, 3.0) = "<<Max(a, b)<<endl;

	system("pause");
	return ;
}

actually , The above procedure , Just one “ function ” You can do it !

// demo 15-3.c
#include <iostream>
using namespace std;
/* int Max(int a, int b) { return a>b ? a:b; } char Max(char a, char b) { return a>b ? a:b; } float Max(float a, float b) { return a>b ? a:b; } */

//template  Keyword telling C++ compiler   I'm going to start generic programming , Please don't make mistakes at will 
//T -  Parameterized data type 
template <typename T>
T Max(T a, T b){
    
	return a>b ? a:b;
}

/* If T  Use int  Type invocation , It is equivalent to calling the following function  int Max(int a, int b) { return a>b ? a:b; } */


void main()
{
    
	//char a = 'c';
	
	int  x = 1;
	int	 y = 2;
	cout<<"max(1, 2) = "<<Max(x, y)<<endl; // Realize the automatic derivation of parameter types 
	cout<<"max(1, 2) = "<<Max<int>(x,y)<<endl;// Display type call 

	float a = 2.0;
	float b = 3.0;
  
	cout<<"max(2.0, 3.0) = "<<Max(a, b)<<endl;

	system("pause");
	return ;
}

Function template syntax

The so-called function template , It's actually building a universal function , Its function type and parameter type are not specified specifically , Use a virtual type to represent . This general function is called function template . Any function with the same body can be replaced by this template , You don't have to define multiple functions , Just define once in the template . When a function is called, the system replaces the virtual type in the template according to the type of the argument , Thus, the functions of different functions are realized .

Function template definition form

It consists of three parts : Template description + Function definition + Function template call

template < Type formal parameter table >
type Function name ( Form parameter table )
{
// Statement sequence
}

  1. Template description
    template < Type formal parameter table >
    The form of the type parameter :
    typename T1 , typename T2 , …… , typename Tn
    or class T1 , class T2 , …… , class Tn
    ( notes :typename and class The effect is exactly the same as )

  2. Function definition
    type Function name ( Form parameter table )
    {
    }
    Be careful : The generic parameter of the template description must appear once in the function definition
    Generic type parameters can be used in the function parameter table , You can also use general type parameters

  3. Function template call
    max(a, b); // Explicit type call
    max(a, b); // Automatic data type derivation

4. template function

Function templates and function overloading
5. Function templates and function overloading 
// demo 15-4.c
#include <iostream>
using namespace std;

template <typename T>
void Swap(T &a, T &b){
    
	T t;
	t = a;
	a = b;
	b = t;
	cout<<"Swap  The template function is called "<<endl;
}


/* void Swap(char &a, int &b){ int t; t = a; a = b; b = t; cout<<"Swap  Ordinary functions are called "<<endl; } */

void main(void){
    
	char cNum = 'c';
	int iNum = 65;

	// Case one , Template function and ordinary function coexist , The parameter type matches the ordinary overloaded function better 
	// Call ordinary functions 
	//Swap(cNum, iNum);

	// The second case   There is no ordinary function , Function templates can implicitly convert data types ?
	// Conclusion : No implicit data type conversion is provided , Must be a strict match 
	//Swap(cNum, iNum);

	system("pause");
	return ;
}

The difference between function template and ordinary function :
Both are allowed to coexist
Function templates don't allow automatic type conversion
Ordinary functions can perform automatic type conversion

// demo 15-5.c
#include <iostream>

using namespace std;

// The first edition 
int Max(int a, int b)
{
    
	cout<<" call  int Max(int a, int b)"<<endl;
	return a>b ? a:b;
}

template<typename T>
T Max(T a, T b)
{
    
	cout<<" call  T Max(T a, T b)"<<endl;
	return a>b ? a:b;
}

template <typename T>
T Max(T a, T b, T c){
    
	cout<<" call  T Max(T a, T b, T c)"<<endl;
	return Max(Max(a, b), c);
}

// The second edition 
int Max1(int a, int b)
{
    
	cout<<" call  int Max(int a, int b)"<<endl;
	return a>b ? a:b;
}

template<typename T1, typename T2>
T1 Max1(T1 a, T2 b)
{
    
	cout<<" call  T Max1(T1 a, T2 b)"<<endl;
	return a>b ? a:b;
}


void main(void){
    
	int a = 1;
	int b = 2;

	// When both the function template and the normal function match the call , Choose the normal function first 
	//cout<<"Max(a, b)"<<Max(a, b)<<endl;

	// If you explicitly use function templates , Then use <>  Type list 
	//Max<>(a, b);

	char c = 'a';
	// If the function template will produce a better match , Using function templates 
	//Max1(c, a);
	//Max(1.0, 2.0);

	Max(3.0, 4.0, 5.0);

	system("pause");
	return ;
}

Function templates and ordinary functions together , Call rules :
1 Function templates can be overloaded like ordinary functions
2 C++ The compiler gives priority to ordinary functions
3 If the function template can produce a better match , Then select the template
4 You can restrict the compiler to match only through templates through the syntax of an empty template argument list
5. The compiler does not treat function templates as being able to handle any type of function
6. The compiler generates different functions from function templates through specific types

Use of class templates

1. Why class templates are needed
The definition and use of class templates and function templates are similar , Sometimes , There are two or more classes , Its function is the same , It's just that the data types are different , We can declare a class template through the following statement :
2. The class template is used to parameterize the type of data required by the class
3. Class templates are particularly important in supporting multiple data structures , The representation and algorithm of these data structures are not affected by the type of elements contained

Class template definition

Class template consists of template description and class description
Template description is the same as function template , as follows :
template < Type formal parameter table >
Class declaration

for example :
template
class ClassName
{
//ClassName Member function of
private :
Type DataMember;
}

A single class template uses

// demo 15-8.c
#include <iostream>

using namespace std;

template <typename T>
class A
{
    
public:
	// The argument list of the function uses the virtual type 
	A(T t=0)
	{
    
		this->t = t;
	}
	// The return value of the member function uses the virtual type 
	T &getT()
	{
    
		return t;
	}

private:
	// Member variables use virtual types 
	T t;
};

void printA(A<int> &a){
    
	cout<<a.getT()<<endl;
}

int main(void){
    
	//1. Template classes define class objects , The specified type must be displayed 
	//2. If the template uses a constructor , Follow the calling rules of the constructor of the previous class 
	A<int>  a(666);
	cout<<a.getT()<<endl;

	// Template class as function parameter 
	printA(a);
	system("pause");
	return 0;
}

Inherited class templates use

// demo 15-9.c
#include <iostream>

using namespace std;

// The combination of parent-child classes and template classes in inheritance 
//1. Parent class general class , Subclasses are template classes ,  It is similar to the playing method of ordinary inheritance 
//2. Subclasses are general classes , The parent class is the template class , When inheriting, the type parameter of the parent class must be instantiated in the subclass 
//3. When both parent and child classes are template classes , The virtual type of the subclass can be passed to the parent class 

/*class B { public: B(int b) { this->b = b; } private: int b; }; */

template <typename T>
class A
{
    
public:
	// The argument list of the function uses the virtual type 
	A(T t)
	{
    
		this->t = t;
	}
	// The return value of the member function uses the virtual type 
	T &getT()
	{
    
		return t;
	}

private:
	// Member variables use virtual types 
	T t;
};

template <typename Tb>
class B: public A<int>
{
    
	public:
	B(Tb b):A<Tb>(b)
	{
    
		this->b = b;
	}

private:
	Tb b;

};

void printA(A<int> &a){
    
	cout<<a.getT()<<endl;
}

int main(void){
    
	//1. Template classes define class objects , The specified type must be displayed 
	//2. If the template uses a constructor , Follow the calling rules of the constructor of the previous class 
	A<int>  a(666);
	cout<<a.getT()<<endl;

	B<int> b(888);
	cout<<"b(888): "<<b.getT()<<endl;

	// Template class as function parameter 
	printA(a);
	system("pause");
	return 0;
}

Conclusion : When subclasses inherit from template classes , You need to let the compiler know What is the data type of the parent class

1. Parent class general class , Subclasses are template classes , It is similar to the playing method of ordinary inheritance
2. Subclasses are general classes , The parent class is the template class , When inheriting, the type parameter of the parent class must be instantiated in the subclass
3. When both parent and child classes are template classes , The virtual type of the subclass can be passed to the parent class
4. All class template functions are written outside the class , In a cpp in

// demo 15-9.c
#include <iostream>

using namespace std;


template <typename T>
class A
{
    
public:
	A(T t=0);

	T &getT();

	A operator +(const A &other);

	void print();

private:
	T t;
};

/* class A { public: A(int t=0); int &getT(); A operator +(const A &other); void print(); private: int t; }; */

template <typename T>
A<T>::A(T t)
{
    
		this->t = t;
}

template <typename T>
T &A<T>::getT()
	{
    
		return t;
	}

template <typename T>
A<T> A<T>::operator+(const A<T> &other){
    
		A<T> tmp; // The inner type of a class can be declared or not 
		tmp.t =this->t + other.t;
		return tmp;
	}

template <typename T>
void A<T>::print(){
    
	cout<<this->t<<endl;
}

int main(void){
    
	
	A<int>  a(666), b(888);
	//cout<<a.getT()<<endl;

	A<int> tmp = a + b;

	tmp.print();

	system("pause");
	return 0;
}

summary :
In the same cpp Put the member function of the template class outside the class in the file , The following points need to be noted

1. Declare before function template < Type formal parameter table >
2. The class restricted field before the member function of the class must be accompanied by a virtual parameter list
3. When the returned variable is the object of the template class, you must bring the virtual parameter list
4. When the object of template class appears in the parameter of member function, the virtual parameter list must be brought
5. There is no restriction inside the member function

// demo.h
#pragma once

template <typename T>
class A
{
    
public:
	A(T t=0);

	T &getT();

	A operator +(const A &other);

	void print();

private:
	T t;
};


// demo 15-10.c
#include "demo.h"
#include <iostream>

using namespace std;

template <typename T>
A<T>::A(T t)
{
    
		this->t = t;
}

template <typename T>
T &A<T>::getT()
	{
    
		return t;
	}

template <typename T>
A<T> A<T>::operator+(const A<T> &other){
    
		A<T> tmp; // The inner type of a class can be declared or not 
		tmp.t =this->t + other.t;
		return tmp;
	}

template <typename T>
void A<T>::print(){
    
	cout<<this->t<<endl;
}

int main(void){
    
	
	A<int>  a(666), b(888);
	//cout<<a.getT()<<endl;

	A<int> tmp = a + b;

	tmp.print();

	system("pause");
	return 0;
}

Be careful : When the class template is declared (.h file ) And the implementation (.cpp or .hpp file ) Complete separation , Because of the special implementation of the class template , We should use... When using class templates #include contain Implementation part .cpp or .hpp file .

A special case Friend function

// demo 15-11.c
#include <iostream>

using namespace std;

template <typename T>
class A
{
    
public:
	A(T t=0);

	// Declare a friend function , To achieve two A Class object to add 
	template <typename T>
	friend A<T> addA(const A<T> &a, const A<T> &b);

	T &getT();

	A operator +(const A &other);

	void print();

private:
	T t;
};



template <typename T>
A<T>::A(T t)
{
    
		this->t = t;
}

template <typename T>
T &A<T>::getT()
	{
    
		return t;
	}

template <typename T>
A<T> A<T>::operator+(const A<T> &other){
    
		A tmp; // The inner type of a class can be declared or not 
		tmp.t =this->t + other.t;
		return tmp;
	}

template <typename T>
void A<T>::print(){
    
	cout<<this->t<<endl;
}


//A  Friend function of class , Is its good friend 
template <typename T>
A<T> addA(const A<T> &a, const A<T> &b){
    
	A<T> tmp;
	cout<<"call addA()..."<<endl;
	tmp.t = a.t + b.t;
	return tmp;
}

int main(void){
    
	
	A<int>  a(666), b(888);
	//cout<<a.getT()<<endl;

	A<int> tmp = a + b;
	A<int> tmp1 = addA<int>(a, b);
	
	tmp.print();
	tmp1.print();

	system("pause");
	return 0;
}

Conclusion :
(1) Declare friend functions inside the class , It must be written in the form
template
friend A addA (A &a, A &b);

(2) Friend function implementation Must be written as
template
A add(A &a, A &b)
{
//…
}
(3) Friend function call Must be written as
A c4 = addA(c1, c2);

Template classes and static members
// demo 15-12.c
#include <iostream>

using namespace std;

template <typename T>
class A
{
    
public:
	A(T t=0);

	T &getT();

	A operator +(const A &other);

	void print();

public:
	static int count;
private:
	T t;
};

template <typename T> int A<T>::count = 666;

template <typename T>
A<T>::A(T t)
{
    
	this->t = t;
}

template <typename T>
T &A<T>::getT()
{
    
	return t;
}

template <typename T>
A<T> A<T>::operator+(const A<T> &other){
    
	A tmp; // The inner type of a class can be declared or not 
	tmp.t =this->t + other.t;
	return tmp;
}

template <typename T>
void A<T>::print(){
    
	cout<<this->t<<endl;
}

/* // When our virtual type T By  int  After instantiation , The template classes are as follows : class A { public: A(int t=0); int &getT(); A operator +(const A &other); void print(); public: static int count; private: int t; }; int A::count = 666; A::A(int t) { this->t = t; } int &A::getT() { return t; } A A::operator+(const A &other){ A tmp; // The inner type of a class can be declared or not  tmp.t =this->t + other.t; return tmp; } void A::print(){ cout<<this->t<<endl; } */

/* // When our virtual type T By  float  After instantiation , The template classes are as follows : class A { public: A(float t=0); float &getT(); A operator +(const A &other); void print(); public: static int count; private: float t; }; int A::count = 666; A::A(float t) { this->t = t; } float &A::getT() { return t; } A A::operator+(const A &other){ A tmp; // The inner type of a class can be declared or not  tmp.t =this->t + other.t; return tmp; } void A::print(){ cout<<this->t<<endl; } */

int main(void){
    

	A<int>  a(666), b(888);
	A<int> tmp = a + b;
	//A a(666), b(888);
	//A tmp = a + b;

	A<float> c(777), d(999);

	a.count = 888;

	cout<<"b.count:"<<b.count<<endl;

	cout<<"c.count:"<<c.count<<endl;
	cout<<"d.count:"<<d.count<<endl;
	c.count = 1000;
	cout<<" After modification , d.count:"<<d.count<<endl;

	//tmp.print();

	system("pause");
	return 0;
}

summary :

1. Each template class instantiated from a class template has its own class template data member , All the objects of this template class share one static Data member
2. And non template classes static Data members are the same , Template class static Data members should also be defined and initialized in the scope of the file
3.static Data members can also use virtual type parameters T

Class template Usage Summary

Sum up the above introduction , You can declare and use class templates like this :

  1. First write an actual class .
  2. Name the type to be changed in this class ( Such as int To change to float or char) Use a virtual type name you specify ( In the example above T).
  3. Add a line before the class declaration , The format is :
    template <typename Virtual type parameters >
    Such as :
    template
    class A
    {…}; // The class body
  4. When you define an object with a class template, use the following form :
    Class template name < Actual type name > Object name ;
    or Class template name < Actual type name > Object name ( Argument table column );
    Such as :
    A cmp;
    A cmp(3,7);
  5. If you define member functions outside the class template , It should be written as a class template :
    template <typename Virtual type parameters >
    Function type Class template name < Virtual type parameters >:: Member function name ( Function parameter list column ) {…}
    Some additions to class templates :
  6. The type parameters of a class template can have one or more , Each type must be preceded by typename or class, Such as :
    template <typename T1,typename T2>
    class someclass
    {…};
    When defining the object, substitute the actual type name , Such as :
    someclass<int, char> object;
  7. Just like using classes , When using a class template, pay attention to its scope , Only use it to define objects within its valid scope .
  8. Template classes can also support inheritance , There is a hierarchical relationship , A class template can be used as a base class , Derived template class .
Class template practice

1) Please design an array template class ( Vector ), Finish right int、char、float、double And any custom class and other type elements .
demand
a. Implement constructors
b. Implement the copy constructor
c. Realization cout << operation
d. Implement subscript accessors [] Overload operation of
e. Realization = The number operator overloads

// demo 15-13 Vector.h
#include <iostream>

using namespace std;

template <typename  T>
class Vector
{
    
	//Vector<int> a(10); cout<<a;
	friend ostream &operator<< <T> (ostream &out, const Vector &object);
public:
	Vector(int size = 128); // Constructors 
	Vector(const Vector &object); // copy constructor 
	//Vector<int> a(10); a
	//operator<<()

	int getLength();// Get the number of elements stored internally 

	//Vector<int> a1, a2; a1[0]
	 T& operator[](int index);

	 // Realization = operators overloading 
	 //a1 = a2 = a3;
	 Vector &operator=(const Vector &object);
	~Vector(); // Destructor 

private:
	T *m_base;
	int m_len;
};

// demo 15-13 Vector.cpp
#include <iostream>
using namespace std;
#include "Vector.h"

//cout<<a<<b<<c;
template<typename T>
ostream &operator<<(ostream &out, const Vector<T> &object){
    
	for(int i=0; i<object.m_len; i++){
    
		out << object.m_base[i] << " ";//Student a("18"," Li Xiaohua "); cout<< a<<endl;
	}
	out<<endl;

	return out;
}

template <typename T>
Vector<T>::Vector(int size){
     // Constructors 
	if(size > 0){
    
		m_len = size;
		m_base = new T[m_len];
	}
}
	
template <typename T>
Vector<T>::Vector(const Vector<T> &object){
     // copy constructor 

	// Allocate space according to the number of object elements passed in 
	m_len = object.m_len;
	m_base = new T[m_len];

	// Copy of data 
	for(int i=0; i<m_len; i++){
    
		m_base[i] = object.m_base[i];
	}
}

template <typename T>
int Vector<T>::getLength(){
    
	return m_len;
}

	//Vector<int> a1, a2; a1[0]
template <typename T>
T& Vector<T>::operator[](int index){
    
	return m_base[index];// return *(m_base+index);
}

	 // Realization = operators overloading 
	 //a1 = a2 = a3;
template <typename T>
Vector<T> &Vector<T>::operator=(const Vector<T> &object){
    
	if(m_base != NULL){
    
		delete[] m_base;
		m_base = NULL;
		m_len = 0;
	}

	// Allocate space according to the number of object elements passed in 
	m_len = object.m_len;
	m_base = new T[m_len];

	// Copy of data 
	for(int i=0; i<m_len; i++){
    
		m_base[i] = object.m_base[i];
	}

	return *this; // a3 = a2 = a1; 
}

template <typename T>
Vector<T>::~Vector(){
     // Destructor 
	if(m_base != NULL){
    
		delete[] m_base;
		m_base = NULL;
		m_len = 0;
	}
}
// demo 15-13 13_ Class template practice .cpp
#include <iostream>
using namespace std;

#include "Vector.cpp"

class Student{
    
	friend ostream &operator<<(ostream &out, const Student &object);
public:
	Student(){
    
		age = 0;
		name[0] = '\0';
	}

	Student(int _age, char *_name){
    
		age = _age;
		strcpy_s(name, 64, _name);
	}

	void print(){
    
		cout<<name<<", "<<age<<endl;
	}

	~Student(){
    

	}

private:
	int age;
	char name[64];
};

ostream &operator<<(ostream &out, const Student &object){
    
	out<<"("<<object.name<<" , "<<object.age<<")";
	return out;
}

int main(){
    
	Student s1(18, " Li Xiaohua ");
	Student s2(19, " Wang cannon ");

	Vector<Student *> studentVector(2);

	studentVector[0] = &s1;
	studentVector[1] = &s2;

	/*for(int i=0; i<studentVector.getLength(); i++){ studentVector[i].print(); }*/

	cout<<studentVector<<endl;
	system("pause");

	//ostream cout;
	Vector<int> myVector(10);
	//int a[10]; len: sizeof(a)/sizeof(a[0])
	for(int i=0; i<myVector.getLength(); i++){
    
		myVector[i] = i;
	}

	cout<<myVector<<endl;
	system("pause");

	for(int i=0; i<myVector.getLength(); i++){
    
		cout<<myVector[i]<<endl;
	}

	// Test the copy constructor 
	Vector<int> myIntVector1(myVector);
	cout<<"myIntVector1  The elements in are as follows :"<<endl;
	for(int i=0; i<myIntVector1.getLength(); i++){
    
		cout<<myIntVector1[i]<<endl;
	}
	cout<<"---end---"<<endl;

	// Test assignment operator overloading 
	Vector<int> myIntVector2(1);
	myIntVector2 = myIntVector1;

	cout<<"myIntVector2  The elements in are as follows :"<<endl;
	for(int i=0; i<myIntVector1.getLength(); i++){
    
		cout<<myIntVector1[i]<<endl;
	}
	cout<<"---end---"<<endl;


	Vector<float> myVector1(10);
	//int a[10]; len: sizeof(a)/sizeof(a[0])
	for(int i=0; i<myVector1.getLength(); i++){
    
		myVector1[i] = i*0.1f;
	}

	for(int i=0; i<myVector1.getLength(); i++){
    
		cout<<myVector1[i]<<endl;
	}

	system("pause");
	return 0;
}

原网站

版权声明
本文为[Who can keep company for a long time]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/176/202206250529175923.html