函数模板和类模板 知识点总结 C++程序设计与算法笔记总结(七) 北京大学 郭炜(下)

简介: 函数模板和类模板 知识点总结 C++程序设计与算法笔记总结(七) 北京大学 郭炜(下)

函数模版作为类模板成员

函数模板可以作为类模板的成员函数。类模板中的成员函数也可以是函数模板,允许在不同的实例化类型上进行通用操作。

下面是一个示例,演示了如何在类模板中定义函数模板作为成员函数:

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);
        }
    }
    // 其他成员函数的实现...
};

在上述代码中,MyVector 是一个类模板,其中定义了一个名为 setValue 的成员函数模板。此函数模板接受两个参数,一个是 index 表示要设置值的索引,另一个是 value 表示要设置的值。该函数模板可以适用于不同的数据类型 TU

使用示例:

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

在上述示例中,我们分别创建了一个 MyVector<int> 和一个 MyVector<double> 对象,并使用 setValue 函数模板设置了不同类型的值。

通过在类模板中定义函数模板,可以实现对不同类型的数据进行通用操作,增加了代码的灵活性和复用性。

类模板与派生

• 类模板从类模板派生

• 类模板从模板类派生

• 类模板从普通类派生

• 普通类从模板类派生

类模板可以作为基类用于派生其他类。通过派生,可以在派生类中使用基类的模板参数,并添加额外的成员变量和成员函数。

下面是一个示例,演示了如何使用类模板作为基类进行派生:

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

在上述代码中,MyBaseTemplate 是一个类模板,它有一个模板参数 T 和一个成员变量 data。派生类 MyDerivedTemplate 继承自 MyBaseTemplate<T>,并添加了一个额外的成员变量 additionalData

派生类中的构造函数使用基类的构造函数进行初始化,并将额外的参数传递给派生类的成员变量。

派生类还可以调用基类的成员函数,如示例中的 printData() 函数。使用作用域解析运算符 :: 可以访问基类的成员函数。

使用示例:

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

在上述示例中,我们创建了一个 MyDerivedTemplate<int> 对象,并将值 1020 分别传递给基类和派生类的构造函数。然后,调用派生类的 printAllData() 函数,它会分别打印基类的数据和派生类的额外数据。

通过派生,我们可以在派生类中扩展和特化基类模板的功能,实现更灵活和具体化的代码。

类模板从类模板派生

类模板可以从另一个类模板派生,这样可以在派生类中使用基类的模板参数,并添加额外的模板参数和成员函数。

下面是一个示例,演示了如何从类模板派生另一个类模板:

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

在上述代码中,MyBaseTemplate 是一个类模板,它有一个模板参数 T 和一个成员变量 data。派生类 MyDerivedTemplate 是一个带有两个模板参数 TU 的类模板,它从 MyBaseTemplate<T> 派生而来,并添加了一个额外的模板参数 U 和成员变量 additionalData

派生类中的构造函数使用基类的构造函数进行初始化,并将额外的参数传递给派生类的成员变量。

派生类还可以调用基类的成员函数,使用作用域解析运算符 :: 可以访问基类的成员函数。

使用示例:

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

在上述示例中,我们创建了一个 MyDerivedTemplate<int, double> 对象,并将值 103.14 分别传递给基类和派生类的构造函数。然后,调用派生类的 printAllData() 函数,它会分别打印基类的数据和派生类的额外数据。

通过从类模板派生另一个类模板,可以实现更加灵活和通用的代码结构,同时具备模板参数的扩展能力。

普通类从模板类派生

普通类也可以从模板类派生,这样可以在派生类中使用模板类的具体化版本。派生类不需要显式地指定模板参数,因为已经在模板类中进行了定义。

下面是一个示例,演示了如何从模板类派生普通类:

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

在上述代码中,MyTemplateClass 是一个模板类,它有一个模板参数 T 和一个成员变量 data。派生类 MyDerivedClassMyTemplateClass<int> 派生而来,并添加了一个额外的成员变量 additionalData

派生类的构造函数使用基类的具体化版本 MyTemplateClass<int> 进行初始化,并将额外的参数传递给派生类的成员变量。

派生类可以调用基类的成员函数,使用作用域解析运算符 :: 可以访问基类的成员函数。

使用示例:

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

在上述示例中,我们创建了一个 MyDerivedClass 对象,并将值 1020 分别传递给基类和派生类的构造函数。然后,调用派生类的 printAllData() 函数,它会分别打印基类的数据和派生类的额外数据。

通过从模板类派生普通类,可以使用特定的模板参数类型,而不必在派生类中指定额外的模板参数。这样可以更方便地使用模板类的功能,并提供更具体化的代码实现。

类模板与友员函数

• 函数、类、类的成员函数作为类模板的友元

• 函数模板作为类模板的友元

• 函数模板作为类的友元

• 类模板作为类模板的友元

类模板可以定义友元函数,这样友元函数可以访问类模板的私有成员和保护成员。友元函数可以在类定义内或外定义。

以下是一个示例,演示了如何在类模板中定义和使用友元函数:

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

在上述代码中,MyTemplateClass 是一个类模板,它有一个模板参数 T 和一个私有成员变量 data。类模板中定义了一个友元函数 printData,该函数可以访问 MyTemplateClass 的私有成员变量 data

用户可以在类模板定义内部或外部定义友元函数。在上述示例中,友元函数 printData 的定义位于类模板定义外部,但在定义友元函数时需要使用类模板的具体化版本 MyTemplateClass<U>

使用示例:

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

在上述示例中,我们创建了一个 MyTemplateClass<int> 对象,并将值 10 传递给构造函数。然后,我们调用友元函数 printData,它会打印类模板对象的私有成员变量 data

通过定义友元函数,类模板可以在需要访问私有或保护成员时提供额外的灵活性和扩展性。这使得友元函数可以直接操作类模板对象的内部数据,而无需通过公有接口。

在C++中,函数、类、类的成员函数和函数模板都可以作为类模板的友元。下面分别介绍这些情况:

  1. 函数作为类模板的友元:
template <typename T>
class MyTemplateClass {
    // 声明函数为友元
    friend void myFriendFunction<T>(const MyTemplateClass<T>& obj);
};
template <typename T>
void myFriendFunction(const MyTemplateClass<T>& obj) {
    // 可以访问MyTemplateClass的私有成员和保护成员
}
  1. 类作为类模板的友元:
template <typename T>
class MyFriendClass {
   // ...
};
template <typename T>
class MyTemplateClass {
    // 声明类为友元
    friend class MyFriendClass<T>;
};
  1. 类的成员函数作为类模板的友元:
template <typename T>
class MyTemplateClass {
private:
    T data;
    // 声明类的成员函数为友元
    friend void MyTemplateClass<T>::myFriendMemberFunction();
    void myFriendMemberFunction() {
        // 可以访问MyTemplateClass的私有成员和保护成员
    }
};
  1. 函数模板作为类模板的友元:
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. 类模板作为类模板的友元:
template <typename T>
class MyFriendClass {
   // ...
};
template <typename T>
class MyTemplateClass {
    // 声明类模板为友元
    template <typename U>
    friend class MyFriendClass<U>;
};

以上示例为各种不同情况下如何声明和使用类模板的友元。友元关系允许其他函数、类或成员函数访问类模板中的私有成员和保护成员,从而提供更大的灵活性和扩展性。请根据实际需求选择适合的友元类型。

类模板与静态成员变量

类模板与static成员

• 类模板中可以定义静态成员,那么从该类模板实例化得到的所有类,
都包含同样的静态成员。
#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;
}

输出:

1

1

类模板与静态成员变量

类模板和静态成员变量可以结合使用。可以在类模板中声明和定义静态成员变量,并且所有实例化的类都共享同一个静态成员变量。以下是示例代码:

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

在上述示例中,MyTemplateClass 是一个类模板,其中声明了一个静态成员变量 count。在类模板外部,我们需要对静态成员变量进行定义和初始化,使用类似于普通类的静态成员变量的语法。

main() 函数中,我们创建了几个类模板的实例。每当创建一个实例时,构造函数会自动递增静态成员变量 count。因为静态成员变量是被所有实例共享的,所以每个实例的构造都会影响到所有实例。

最后,我们通过类名加作用域解析运算符 :: 来访问不同类型的静态成员变量,并将其输出到控制台。

总结来说,类模板可以具有静态成员变量,并且所有实例化的类都共享同一个静态成员变量。这在跟踪和计数类模板对象的数量时非常有用。

目录
相关文章
|
算法 安全 搜索推荐
套用算法模板备案审核问题增多的原因及解决建议
随着算法备案要求的完善,企业常因使用网上廉价模板而遭遇审核通过率低、问题增多的困境。本文分析了审核不通过的原因,包括模板缺乏针对性、审核标准严格、审核人员主观差异及企业准备不足等,并提出建议:深入了解备案要求、准备详尽材料、避免通用模板、寻求专业帮助。备案后还需持续合规管理,确保算法服务安全运行。
|
JSON 算法 数据可视化
测试专项笔记(一): 通过算法能力接口返回的检测结果完成相关指标的计算(目标检测)
这篇文章是关于如何通过算法接口返回的目标检测结果来计算性能指标的笔记。它涵盖了任务描述、指标分析(包括TP、FP、FN、TN、精准率和召回率),接口处理,数据集处理,以及如何使用实用工具进行文件操作和数据可视化。文章还提供了一些Python代码示例,用于处理图像文件、转换数据格式以及计算目标检测的性能指标。
412 0
测试专项笔记(一): 通过算法能力接口返回的检测结果完成相关指标的计算(目标检测)
|
算法 API 计算机视觉
人脸识别笔记(一):通过yuface调包(参数量54K更快更小更准的算法) 来实现人脸识别
本文介绍了YuNet系列人脸检测算法的优化和使用,包括YuNet-s和YuNet-n,以及通过yuface库和onnx在不同场景下实现人脸检测的方法。
791 1
|
数据可视化 搜索推荐 Python
Leecode 刷题笔记之可视化六大排序算法:冒泡、快速、归并、插入、选择、桶排序
这篇文章是关于LeetCode刷题笔记,主要介绍了六大排序算法(冒泡、快速、归并、插入、选择、桶排序)的Python实现及其可视化过程。
348 0
|
算法
❤️算法笔记❤️-(每日一刷-83、删除排序链表中的重复项)
❤️算法笔记❤️-(每日一刷-83、删除排序链表中的重复项)
222 0
|
6月前
|
机器学习/深度学习 算法 机器人
使用哈里斯角Harris和SIFT算法来实现局部特征匹配(Matlab代码实现)
使用哈里斯角Harris和SIFT算法来实现局部特征匹配(Matlab代码实现)
292 8
|
6月前
|
机器学习/深度学习 算法 自动驾驶
基于导向滤波的暗通道去雾算法在灰度与彩色图像可见度复原中的研究(Matlab代码实现)
基于导向滤波的暗通道去雾算法在灰度与彩色图像可见度复原中的研究(Matlab代码实现)
338 8
|
6月前
|
机器学习/深度学习 算法 机器人
【水下图像增强融合算法】基于融合的水下图像与视频增强研究(Matlab代码实现)
【水下图像增强融合算法】基于融合的水下图像与视频增强研究(Matlab代码实现)
589 0
|
6月前
|
机器学习/深度学习 数据采集 负载均衡
结合多种启发式解码方法的混合多目标进化算法,用于解决带工人约束的混合流水车间调度问题(Matlab代码实现)
结合多种启发式解码方法的混合多目标进化算法,用于解决带工人约束的混合流水车间调度问题(Matlab代码实现)
307 0
|
6月前
|
机器学习/深度学习 人工智能 算法
【基于TTNRBO优化DBN回归预测】基于瞬态三角牛顿-拉夫逊优化算法(TTNRBO)优化深度信念网络(DBN)数据回归预测研究(Matlab代码实现)
【基于TTNRBO优化DBN回归预测】基于瞬态三角牛顿-拉夫逊优化算法(TTNRBO)优化深度信念网络(DBN)数据回归预测研究(Matlab代码实现)
270 0

热门文章

最新文章

下一篇
开通oss服务