Summary of Knowledge Points of Function Templates and Class Templates Summary of C++ Programming and Algorithm Notes (7) Guo Wei, Peking University

insert image description here

function template

交换两个整型变量的值的Swap函数:
void Swap(int & x,int & y) 
{
    
    
int tmp = x;
x = y;
y = tmp;
}
交换两个double型变量的值的Swap函数:
void Swap(double & x,double & y) 
{
    
    
double tmp = x;
x = y;
y = tmp;
}

Solved with function templates:

用函数模板解决:
template <class 类型参数1class 类型参数2,……>
返回值类型 模板名 (形参表)
{
    
    
函数体
};
template <class T>
void Swap(T & x,T & y) 
{
    
    
T tmp = x;
x = y;
y = tmp;
}
函数模板
int main()
{
    
    
int n = 1,m = 2;
Swap(n,m); //编译器自动生成 void Swap(int & ,int & )函数
double f = 1.2,g = 2.3;
Swap(f,g); //编译器自动生成 void Swap(double & ,double & )函数
return 0;
}
void Swap(double & x,double & y) 
{
    
    
double tmp = x;
x = y;
y = tmp

In C++, a function template is a generic function definition that can be applied to different data types. It allows writing code once to accommodate many different data types, enabling code reuse and generalization.

A function template begins with the keyword "template" followed by a list of template parameters. A template parameter list can contain one or more type parameters (such as T, U, etc.) or non-type parameters (such as integer constants). For example:

template <typename T>
T max(T a, T b) {
    
    
    return (a > b) ? a : b;
}

The function template in the code above maxtakes two arguments of the same type and returns the larger value. Type parameters Tcan be of any data type, such as integers, floats, characters, etc.

When the function template is actually called, the compiler instantiates the template according to the type of the parameter and generates a function of the corresponding type. For example:

int result1 = max<int>(3, 5);      // 实例化为 max<int>, 返回 5
double result2 = max<double>(2.7, 1.5);  // 实例化为 max<double>, 返回 2.7
char result3 = max<char>('a', 'b');     // 实例化为 max<char>, 返回 'b'

In the above example, <类型>the specific type of instantiation is specified in the form of , so that the compiler can generate the corresponding function according to the type passed in. If no type is explicitly specified, the compiler will automatically deduce the instantiated type based on the type of the parameter.

Function templates can also have multiple type parameters, and can have default parameter values. In addition, you can also define non-template functions outside of function templates, and they can be overloaded with function templates.

Function template is a powerful tool in C++, which can be used to write general-purpose and reusable code that can handle different types of data.

Multiple type parameters can be used when multiple parameters of different types need to be handled in a function template.

For example, here is a function template swapfor swapping two values:

template <typename T>
void swap(T& a, T& b) {
    
    
    T temp = a;
    a = b;
    b = temp;
}

The function template in the above code swaptakes two reference parameters of the same type and swaps their values. When using this function template, the compiler will instantiate the corresponding function according to the type of the actual parameter.

int x = 5, y = 10;
swap(x, y);  // 实例化为 swap<int>(x, y),交换 x 和 y 的值

double a = 2.5, b = 3.7;
swap(a, b);  // 实例化为 swap<double>(a, b),交换 a 和 b 的值

In addition to type parameters, function templates can also contain non-type parameters. A non-type parameter can be of integer, enumeration, pointer, or reference type, but not of floating point, class type, or void type.

Here's an example of how to use a non-type parameter in a function template to specify the size of an array:

template <typename T, int size>
void printArray(const T (&arr)[size]) {
    
    
    for (int i = 0; i < size; ++i) {
    
    
        cout << arr[i] << " ";
    }
    cout << endl;
}

The function template in the above code printArraytakes a fixed-size array and prints each element. The size of the array can be known at compile time by passing the size of the array as a non-type parameter to the function template.

int intArray[] = {
    
    1, 2, 3, 4, 5};
printArray(intArray);  // 实例化为 printArray<int, 5>(intArray)

double doubleArray[] = {
    
    1.5, 2.7, 3.9};
printArray(doubleArray);  // 实例化为 printArray<double, 3>(doubleArray)

In this way, the function template can generate corresponding functions according to different array sizes.

It should be noted that in the definition and declaration of function templates, template parameters are usually placed in angle brackets < >, and the keywords typenameor are used classto declare type parameters. However, you can also use non-type parameters to tune the template's behavior.

At the same time, function templates can also have default template parameters for more flexible use. The default template parameter allows to specify the default value of one or some parameters, so that these parameters can be omitted when the function is called.

Function templates in C++ are a powerful tool that can handle multiple parameters of different types, which can contain type parameters and non-type parameters. By using function templates, common and reusable code can be realized, and corresponding functions can be automatically generated according to the type and value of actual parameters.

Order of function templates and functions

In the case where there are multiple functions with the same name as the function template, the compiler processes a function call statement as follows

  1. First find a normal function (a function not instantiated from a template) whose parameters completely match.
  2. Then find a template function whose parameters completely match.
  3. Then find an ordinary function that can match the real parameters after automatic type conversion.
  4. If none of the above can be found, an error will be reported.

class template

Class Templates – Proposed Questions
• In order to define a batch of similar classes quickly and economically, you can define class templates, and then
generate different classes from the class templates
• Array is a common data type, and its elements can be:
– Integer
– Student
– ​​String
– ……
• Consider a variable-length array class, the basic operations that need to be provided
– len(): check the length of the array
– getElement(int index): get one of the elements
– setElement(int index) : Assign a value to one of the elements
–  …

### Definition of class template

template <typename 类型参数1typename 类型参数2,……>
//类型参数表
class 类模板名
{
    
    
成员函数和成员变量
};

类模板里成员函数的写法:
template <class 类型参数1class 类型参数2,……> //类型参数表
返回值类型 类模板名<类型参数名列表>::成员函数名(参数表)
{
    
     
……
}


用类模板定义对象的写法:
类模板名 <真实类型参数表> 对象名(构造函数实参表);
类模板示例: Pair类模板
template <class T1,class T2>
class Pair
{
    
    
public:
T1 key; //关键字
T2 value; //值
Pair(T1 k,T2 v):key(k),value(v) {
    
     };
bool operator < ( const Pair<T1,T2> & p) const; 
};
template<class T1,class T2>
bool Pair<T1,T2>::operator < ( const Pair<T1,T2> & p) const 
//Pair的成员函数 operator <
{
    
     
return key < p.key; 
}

Class template example: Pair class template

int main()
{
    
    
Pair<string,int> student("Tom",19); 
//实例化出一个类 Pair<string,int>
cout << student.key << " " << student.value; 
return 0;
}
输出:
Tom 19

Class template (Class Template) is another general programming tool in C++, which allows to define a general class that can be used for different data types.

A class template templatebegins with the keyword and < >encloses one or more type parameters in angle brackets. Type parameters can be used as placeholders for types inside class definitions. For example:

template <typename T>
class MyStack {
    
    
private:
    T* elements;
    int top;
    int capacity;

public:
    MyStack(int size) {
    
    
        elements = new T[size];
        capacity = size;
        top = -1;
    }

    // 其他成员函数的实现省略...
};

The class template in the above code MyStackdefines a stack data structure, in which the element type Tis a placeholder, which will be instantiated according to the type passed in during actual use.

When actually using a class template, it is necessary to explicitly instantiate a specific type of class according to actual needs. For example:

MyStack<int> intStack(10);       // 实例化为 MyStack<int>
MyStack<double> doubleStack(5);  // 实例化为 MyStack<double>

In the above code, a inttype and an object doubleof type are created respectively MyStack. Each object is a class instantiated according to the corresponding type.

Class templates can also have multiple type parameters, and can contain non-type parameters, similar to function templates. You can either explicitly specify the instantiated type by providing an argument of a specific type, or let the compiler deduce the type automatically.

Class templates can also have member functions, member variables, constructors, and destructors, etc., which can be implemented according to specific requirements. When defining a member function of a class template, you can use it like a normal class to refer Tto the type represented by the template parameter.

template <typename T>
class MyStack {
    
    
    // ...

    void push(T element) {
    
    
        if (top + 1 >= capacity) {
    
    
            // 扩展容量代码...
        }
        elements[++top] = element;
    }

    T pop() {
    
    
        if (top < 0) {
    
    
            // 异常处理代码...
        }
        return elements[top--];
    }

    // ...
};

To summarize, a class template is a tool in C++ for defining generic classes, allowing the creation of classes that can accommodate different data types. A class template is templatedefined using keywords and type parameters and produces a class of a specific type through explicit instantiation or type deduction. Class templates can also contain member functions, member variables, etc., for processing specific types of data.

Define objects with class templates

The process by which the compiler generates classes from class templates is called instantiation of class templates. A class obtained by instantiating a class template is called a template class.

Two template classes of the same class template are incompatible

Two template classes of the same class template are incompatible

Yes, for the same class template, different template instances (i.e. different template parameters) generate different types, which are completely independent and incompatible at compile time.

For example, consider the following class template MyStack:

template <typename T>
class MyStack {
    
    
    // ...
};

MyStack<int>Objects instantiated using and MyStack<double>objects instantiated using are completely different types and are not compatible between them.

MyStack<int> intStack;
MyStack<double> doubleStack;

intStack.push(5);
doubleStack.push(3.14);

int x = intStack.pop();         // 类型为 int
double y = doubleStack.pop();   // 类型为 double

In the above code, intStackand doubleStackare two completely different objects, their behavior and type are determined according to the template parameters at the time of instantiation.

Since the types generated by different template instances are incompatible, you cannot MyStack<int>assign MyStack<double>objects of to objects of , nor mix them.

MyStack<int> intStack;
MyStack<double> doubleStack;

// 以下代码是不允许的,会导致类型错误:
doubleStack = intStack;          // 错误:不兼容的类型
double x = intStack.pop();       // 错误:类型不匹配
intStack.push(3.14);             // 错误:类型不匹配

Therefore, for different template instances generated by the same class template, they are not compatible, and you need to pay attention to keep the types consistent when using them.

Function templates as class template members

Function templates can be used as member functions of class templates. Member functions in class templates can also be function templates, allowing generic operations on different instantiated types.

Here is an example showing how to define a function template as a member function in a class template:

template <typename T>
class MyVector {
    
    
private:
    T* elements;
    int size;

public:
    MyVector(int s) : size(s) {
    
    
        elements = new T[size];
    }

    template <typename U>
    void setValue(int index, U value) {
    
    
        if (index >= 0 && index < size) {
    
    
            elements[index] = static_cast<T>(value);
        }
    }

    // 其他成员函数的实现...
};

In the above code, MyVectoris a class template that defines a setValuemember function template named . This function template accepts two parameters, one is indexthe index of the value to be set, and the other is valuethe value to be set. The function template can be applied to different data types Tand U.

Example usage:

MyVector<int> myIntVector(5);
myIntVector.setValue(0, 10);          // 设置索引0处的值为10

MyVector<double> myDoubleVector(3);
myDoubleVector.setValue(1, 3.14);     // 设置索引1处的值为3.14

In the above example, we created a MyVector<int>and a MyVector<double>object respectively, and setValueset values ​​of different types using the function template.

By defining function templates in class templates, common operations on different types of data can be realized, which increases the flexibility and reusability of codes.

Class Templates and Derivation

• class template derived from class template
• class template derived from template class
• class template derived from normal class
• normal class derived from template class

A class template can be used as a base class for deriving other classes. Through derivation, you can use the template parameters of the base class in the derived class and add additional member variables and member functions.

Here's an example that demonstrates how to use a class template as a base class for derivation:

template <typename T>
class MyBaseTemplate {
    
    
protected:
    T data;

public:
    MyBaseTemplate(const T& value) : data(value) {
    
    }

    void printData() const {
    
    
        std::cout << "Data: " << data << std::endl;
    }
};

template <typename T>
class MyDerivedTemplate : public MyBaseTemplate<T> {
    
    
private:
    int additionalData;

public:
    MyDerivedTemplate(const T& value, int additional) : MyBaseTemplate<T>(value), additionalData(additional) {
    
    }

    void printAllData() const {
    
    
        MyBaseTemplate<T>::printData();
        std::cout << "Additional Data: " << additionalData << std::endl;
    }
};

In the above code, MyBaseTemplateis a class template, it has a template parameter Tand a member variable data. Derived classes MyDerivedTemplateinherit from MyBaseTemplate<T>and add an extra member variable additionalData.

Constructors in derived classes use base class constructors for initialization and pass additional parameters to derived class member variables.

Derived classes can also call member functions of the base class, such as the function in the example printData(). Use the scope resolution operator ::to access member functions of the base class.

Example usage:

MyDerivedTemplate<int> myDerived(10, 20);
myDerived.printAllData();

In the above example, we created a MyDerivedTemplate<int>object and passed the values 10​​and 20to the base and derived class constructors respectively. Then, call printAllData()the function of the derived class, which will print the data of the base class and the extra data of the derived class, respectively.

Through derivation, we can extend and specialize the functions of the base class template in the derived class to achieve more flexible and specific code.

A class template is derived from a class template

A class template can derive from another class template, so that the base class's template parameters can be used in the derived class, and additional template parameters and member functions can be added.

Here's an example that demonstrates how to derive another class template from a class template:

template <typename T>
class MyBaseTemplate {
    
    
protected:
    T data;

public:
    MyBaseTemplate(const T& value) : data(value) {
    
    }

    void printData() const {
    
    
        std::cout << "Data: " << data << std::endl;
    }
};

template <typename T, typename U>
class MyDerivedTemplate : public MyBaseTemplate<T> {
    
    
private:
    U additionalData;

public:
    MyDerivedTemplate(const T& value, const U& additional) : MyBaseTemplate<T>(value), additionalData(additional) {
    
    }

    void printAllData() const {
    
    
        MyBaseTemplate<T>::printData();
        std::cout << "Additional Data: " << additionalData << std::endl;
    }
};

In the above code, MyBaseTemplateis a class template, it has a template parameter Tand a member variable data. Derived class is a class template MyDerivedTemplatewith two template parameters Tand , which is derived from and adds an additional template parameter and member variables .UMyBaseTemplate<T>UadditionalData

Constructors in derived classes use base class constructors for initialization and pass additional parameters to derived class member variables.

The derived class can also call the member functions of the base class, and use the scope resolution operator ::to access the member functions of the base class.

Example usage:

MyDerivedTemplate<int, double> myDerived(10, 3.14);
myDerived.printAllData();

In the above example, we created a MyDerivedTemplate<int, double>object and passed the values 10​​and 3.14to the base and derived class constructors respectively. Then, call printAllData()the function of the derived class, which will print the data of the base class and the extra data of the derived class, respectively.

By deriving another class template from a class template, a more flexible and general code structure can be achieved, and at the same time, it has the ability to expand template parameters.

Ordinary classes are derived from template classes

Ordinary classes can also be derived from template classes, so that a reified version of the template class can be used in the derived class. Derived classes do not need to explicitly specify template parameters because they are already defined in the template class.

Here's an example that demonstrates how to derive a normal class from a template class:

template <typename T>
class MyTemplateClass {
    
    
protected:
    T data;

public:
    MyTemplateClass(const T& value) : data(value) {
    
    }

    void printData() const {
    
    
        std::cout << "Data: " << data << std::endl;
    }
};

class MyDerivedClass : public MyTemplateClass<int> {
    
    
private:
    int additionalData;

public:
    MyDerivedClass(const int& value, int additional) : MyTemplateClass<int>(value), additionalData(additional) {
    
    }

    void printAllData() const {
    
    
        MyTemplateClass<int>::printData();
        std::cout << "Additional Data: " << additionalData << std::endl;
    }
};

In the above code, MyTemplateClassis a template class, which has a template parameter Tand a member variable data. Derived classes are derived MyDerivedClassfrom MyTemplateClass<int>with an additional member variable added additionalData.

MyTemplateClass<int>The constructor of the derived class is initialized with the reified version of the base class , and additional parameters are passed to the member variables of the derived class.

The derived class can call the member functions of the base class, and use the scope resolution operator ::to access the member functions of the base class.

Example usage:

MyDerivedClass myDerived(10, 20);
myDerived.printAllData();

In the above example, we created a MyDerivedClassobject and passed the values 10​​and 20to the base and derived class constructors respectively. Then, call printAllData()the function of the derived class, which will print the data of the base class and the extra data of the derived class, respectively.

By deriving a general class from a template class, you can use specific template parameter types without having to specify additional template parameters in the derived class. This makes it easier to use the functionality of template classes and provides more specific code implementations.

Class templates and friend functions

• Functions, classes, member functions of classes as friends of class templates
• Function templates as friends of class templates
• Function templates as friends of classes
• Class templates as friends of class templates

Class templates can define friend functions so that friend functions can access private and protected members of the class template. Friend functions can be defined inside or outside the class definition.

Here is an example that demonstrates how to define and use friend functions in class templates:

template <typename T>
class MyTemplateClass {
    
    
private:
    T data;

public:
    MyTemplateClass(const T& value) : data(value) {
    
    }

    template <typename U>
    friend void printData(const MyTemplateClass<U>& obj);
};

template <typename U>
void printData(const MyTemplateClass<U>& obj) {
    
    
    std::cout << "Data: " << obj.data << std::endl;
}

In the above code, MyTemplateClassis a class template, it has a template parameter Tand a private member variable data. A friend function is defined in the class template printData, which can access MyTemplateClassprivate member variables of data.

Users can define friend functions inside or outside the class template definition. In the above example, printDatathe definition of the friend function is outside the definition of the class template, but the reified version of the class template is required when defining the friend function MyTemplateClass<U>.

Example usage:

MyTemplateClass<int> obj(10);
printData(obj);

In the above example, we created a MyTemplateClass<int>object and 10passed the value to the constructor. Then, we call the friend function printData, which prints the private member variables of the class template object data.

By defining friend functions, class templates can provide additional flexibility and extensibility when access to private or protected members is required. This allows friend functions to directly manipulate the internal data of class template objects without going through the public interface.

In C++, functions, classes, member functions of classes, and function templates can all be used as friends of class templates. These situations are described below:

  1. Functions as friends of class templates:
template <typename T>
class MyTemplateClass {
    
    
    // 声明函数为友元
    friend void myFriendFunction<T>(const MyTemplateClass<T>& obj);
};

template <typename T>
void myFriendFunction(const MyTemplateClass<T>& obj) {
    
    
    // 可以访问MyTemplateClass的私有成员和保护成员
}
  1. Classes as friends of class templates:
template <typename T>
class MyFriendClass {
    
    
   // ...
};

template <typename T>
class MyTemplateClass {
    
    
    // 声明类为友元
    friend class MyFriendClass<T>;
};
  1. A member function of a class acts as a friend of the class template:
template <typename T>
class MyTemplateClass {
    
    
private:
    T data;

    // 声明类的成员函数为友元
    friend void MyTemplateClass<T>::myFriendMemberFunction();
    
    void myFriendMemberFunction() {
    
    
        // 可以访问MyTemplateClass的私有成员和保护成员
    }
};
  1. Function templates as friends of class templates:
template <typename T>
class MyTemplateClass {
    
    
    // 声明函数模板为友元
    template <typename U>
    friend void myFriendFunctionTemplate(const MyTemplateClass<U>& obj);
};

template <typename U>
void myFriendFunctionTemplate(const MyTemplateClass<U>& obj) {
    
    
    // 可以访问MyTemplateClass的私有成员和保护成员
}
  1. Class templates as friends of class templates:
template <typename T>
class MyFriendClass {
    
    
   // ...
};

template <typename T>
class MyTemplateClass {
    
    
    // 声明类模板为友元
    template <typename U>
    friend class MyFriendClass<U>;
};

The above examples show how to declare and use the friends of the class template in various situations. Friendship allows other functions, classes, or member functions to access private and protected members in a class template, providing greater flexibility and extensibility. Please select a suitable friend type according to actual needs.

Class templates and static member variables

Class templates and static members

• 类模板中可以定义静态成员,那么从该类模板实例化得到的所有类,
都包含同样的静态成员。
#include <iostream>
using namespace std;
template <class T>
class A
{
    
    
private:
static int count;
public:
A() {
    
     count ++; }
~A() {
    
     count -- ; };
A( A & ) {
    
     count ++ ; }
static void PrintCount() {
    
     cout << count << endl; }
};
类模板与static成员
template<> int A<int>::count = 0;
template<> int A<double>::count = 0;
int main()
{
    
    
A<int> ia;
A<double> da;
ia.PrintCount();
da.PrintCount();
return 0;
}

Output:
1
1

Class templates and static member variables

Class templates and static member variables can be used in conjunction. Static member variables can be declared and defined in class templates, and all instantiated classes share the same static member variable. Here is sample code:

template <typename T>
class MyTemplateClass {
    
    
public:
    static int count; // 声明静态成员变量

    MyTemplateClass() {
    
    
        count++; // 在构造函数中对静态成员变量进行操作
    }
};

template <typename T>
int MyTemplateClass<T>::count = 0; // 静态成员变量的定义和初始化

int main() {
    
    
    MyTemplateClass<int> obj1;
    MyTemplateClass<int> obj2;
    MyTemplateClass<double> obj3;

    std::cout << "Count for int: " << MyTemplateClass<int>::count << std::endl; // 输出2
    std::cout << "Count for double: " << MyTemplateClass<double>::count << std::endl; // 输出1

    return 0;
}

In the above example, MyTemplateClassit is a class template in which a static member variable is declared count. Outside the class template, we need to define and initialize static member variables, using syntax similar to static member variables of ordinary classes.

In main()the function, we create several instances of the class template. The constructor automatically increments the static member variables whenever an instance is created count. Because static member variables are shared by all instances, the construction of each instance affects all instances.

::Finally, we access different types of static member variables through the class name plus the scope resolution operator , and output them to the console.

To summarize, a class template can have static member variables, and all instantiated classes share the same static member variable. This is useful when tracking and counting the number of class template objects.

Guess you like

Origin blog.csdn.net/shaozheng0503/article/details/131458395