C++学习笔记_11 模板编程 2021-04-29

简介: C++学习笔记_11 模板编程 2021-04-29
// C++学习笔记_11 模板编程 
#include<cstdio>
#include<iostream>
#include<string>
using namespace std;
/*
//交换两个整数变量的值
void swap(int &a, int &b)
{ 
  int tmp = a;a = b; b = tmp;
}
//我们想交换两个字符串的值?
void swap(string& s1, string& s2)
{
    string ss = s1;s1 = s2;s2 = ss;
}
*/
//交换两个double变量? 交换两个其他对象?...
//每个都实现一个交换函数? --- 这些交换函数,实现的方式都是一样的
//----》 低效
//---》 使用模板来实现这个函数
template<typename T>  //声明下面的函数,是一个模板函数, T 是我们待定类型
                      //T 成为模板参数
        //有些比较老的教材,写的是 template<class T> ....
        //不建议大家使用class的方式:typename 是新标准,class 在模板定义时候,有特定的用法
void swap(T &a, T &b)
{
    //写法和上面一样,只是变量类型使用 T 来替换
    // --> T 是一个待定的数据类型
    // --> 调用的时候,入参是什么类型,则自动生成一个对应类型的函数,给我们调用
    cout << "MySwap ..." << endl;
    T tmp = a;a = b;b = tmp;
}
//如果,我们待定的入参类型有多个,我们可以使用多个T
template <typename T1, typename T2>
void PrintKeyValue(T1 &key, T2 &value)
{
    cout << "K-V: " << key << " -> " << value << endl;
}
class AAA{
private:
    int x;
    int y;
public:
    AAA() :x(0), y(0){}
    AAA(int a, int b) :x(a), y(b){}
    friend ostream& operator << (ostream& os, const AAA &A)
    {
        os << "(" << A.x << "," << A.y << ")";
        return os;
    }
};
void TestTemplate()
{
    int a = 10;
    int b = 20;
    //“std::swap”: 对重载函数的调用不明确  
    // std 这个命名空间中,也定义了 swap 函数,而且我们已经使用了std 这个命名空间
    // --》调用 swap 产生了歧义:两个swap,不知道调用哪一个
    // --> 怎么解决?
    //    --> 声明作用域!!!
    //       --> 使用 std 里面的swap    --》 std::swap
    //       --> 使用 文件中定义的swap  --》 ::swap
    std::swap(a, b);
    cout << "(a, b) = (" << a << "," << b << ")" << endl << endl;
    ::swap(a, b); //调用自己定义的swap
    cout << "(a, b) = (" << a << "," << b << ")" << endl << endl;
    string s1("ABCD");
    string s2("1234");
    ::swap<string>(s1, s2); //可以显示指定 string 类型,也可以省略
    cout << "(s1,s2) = (" << s1 << "," << s2 << ")" << endl << endl;
    AAA A1;
    AAA A2(1, 2);
    ::swap(A1, A2);
    //cout << A1;  --> cout 对于运算符重载函数(<<) 里面的 os参数, A1 对应这个函数的 A参数
    cout << "A1:" << A1 << endl;
    cout << "A2:" << A2 << endl << endl;
    //这里 这个 swap 我们称之为 模板函数 (函数模板)
    //--》模板函数不是一个正常的函数
    //    一个正常函数,占用多大空间,是确定的
    // -->我们调用模板函数的时候-->根据入参类型匹配,自动生成一个对于的具体函数
    //    调用具体函数来处理我们的数据
}
//对于类,同样的,我们也可以写成模板的形式(内部的变量类型待定)
template <typename T1, typename T2>
class BBB
{
private:
    T1 x;
    T2 y;
public:
    BBB(T1 a, T2 b) :x(a), y(b){  }
    //重载 输出运算符 << 
    //调用 << 的对象是 os 对象,它需要访问 BBB 的私有成员
    // --》 所以,这里需要使用 friend
    friend ostream& operator << (ostream &os, const BBB B)
    {
        os << "Class 0:";
        os << "(" << B.x << "," << B.y << ")";
        return os;
    }
};
void TestBBB()
{
    //error C2955: “BBB”: 使用 类 模板 需要 模板 参数列表
    //这里不能使用 BBB 来生成对象
    //为什么? --》BBB 是一个类模板,不是具体的类, 不能够生成对象
    //--> 需要使用模板参数列表,生成一个具体类
    //--》模板函数调用前,入参类型是已知的,程序会自动推导,生成函数(可以省略模板参数)
    //--》模板类 生成对象的时候,如果,不指定具体类,程序不知到要调用哪个构造函数
    //BBB<int, int>   -->指定参数列表 template<typename T1, typename T2> 里面
    //                   T1 是 int, T2 也是 int
    // ---》 这里 BBB<int, int> 就是一个具体的类 (通过模板类来生成的)
    //       通过指定 模板参数 --》生成一个具体类
    //我们可以随意的指定 T1,T2 具体是什么参数类型,
    //   指定不同的参数类型,就会生成不同的 具体类
    BBB<int, int>    B1(1, 2);     //使用 BBB<int, int> 类,构造 B1对象
    BBB<int, string> B2(3, "ABC");
    //这里 B1, B2 的变量类型是不一样的!!!!!!!!!
    cout << "B1:" << B1 << endl;
    cout << "B2:" << B2 << endl;
}
template <typename T>
const T& Max(const T& a, const T& b)
{
    return a > b ? a : b;
}
template<>  //声明这是一个模板函数  
            //--》称之为 偏特化: 模板函数的特殊情况特殊处理
            //-->调用模板函数的时候,优先调用更加匹配的函数
const string& Max(const string& a, const string& b)
{
    return a.length() > b.length() ? a : b;
}
void TestMax()
{
    //error C2440: “return”: 无法从“const int”转换为“int &”
    //调用Max(10,20)的时候,入参赋值  const int& a = 10, const int& b = 10
    //   -->引用是不能直接赋值的  (只能用变量进行赋值[别名])
    //cout << "Max(10, 20): "<< Max(10, 20) << endl;
    int x = 10;
    int y = 20;
    cout << "Max(10, 20): " << Max(x, y) << endl;
    double d1 = 1.1;
    double d2 = 1.2;
    cout << "Max(1.1, 1.2): " << Max(d1, d2) << endl;
    string s1 = "ABCD";
    string s2 = "Abc";
    cout << "Max(\"ABCD\", \"Abc\"): " << Max(s1, s2) << endl;
    //--> 字符串比较大小:逐个字符比较 ASCII 码,遇到第一对不相等的字符
    //    返回这一对字符的比较结果 (也叫字典比较)
    //新的问题:如果我们比较字符串的时候,想对长度进行比较 ?
    //           Max(s1, s2)  返回 长的字符串
    //---》 使用函数的偏特化,特殊的模板参数特殊处理
}
//同样的,我们也可以对模板类进行偏特化. 比如 CCC, 有两个模板参数 T1,T2
template <typename T1, typename T2>
class CCC
{
private:
    T1 x;
    T2 y;
public:
    CCC(T1 a, T2 b) :x(a), y(b){}
    //重载 输出运算符 << 
    //调用 << 的对象是 os 对象,它需要访问 BBB 的私有成员
    // --》 所以,这里需要使用 friend
    friend ostream& operator << (ostream &os, const CCC C)
    {
        os << "Class 0-";
        os << "(" << C.x << "," << C.y << ")";
        return os;
    }
};
//偏特化1: 第二个模板参数是 int 的情况
//          只能从后面开始,类似于定义 函数入参的默认值
template<typename T>
class CCC<T, int>       //声明偏特化的类型 : 声明偏特化的时候,把偏特化的那个类型,放到 <> 后面部分
{
private:
    T     x;
    int   y;
public:
    CCC(T a, int b) :x(a), y(b){}
    friend ostream& operator << (ostream &os, const CCC &C)
    {
        os << "Class 1-";
        os << "(" << C.x << ", " << C.y << ")";
        return os;
    }
};
//偏特化2:两个模板参数,参数类型一样
template<typename T>
class CCC<T, T>   // <T, T> 声明这个特化,两个T类型一样
{
private:
    T x;
    T y;
public:
    CCC(T a, T b) :x(a), y(b){}
    friend ostream& operator << (ostream &os, const CCC &C)
    {
        os << "Class 2-";
        os << "(" << C.x << ", " << C.y << ")";
        return os;
    }
};
//偏特化3:更加具体的偏特化--两个 模板类型都是 int
template<>
class CCC<int, int>
{
private:
    int x;
    int y;
public:
    CCC(int a, int b) :x(a), y(b){}
    friend ostream& operator << (ostream &os, const CCC &C)
    {
        os << "Class 3-";
        os << "(" << C.x << ", " << C.y << ")";
        return os;
    }
};
void TestSpecial()
{
    CCC<int, string>     C1(123, "ABC"); //没有偏特化
    CCC<string, int>     C2("Hello", 12);  //第二个是 int 的偏特化
    CCC<double, double>  C3(1.1, 2.2);        //两个类型一样的偏特化
    CCC<string, string>  C4("Hello", "World"); //两个类型一样的偏特化
    //error C2752 : “CCC<int, int>” : 多个部分专用化与模板参数列表匹配
    CCC<int, int>        C5(1, 2); //既匹配 CCC<T,int> 也匹配 CCC<T,T>
                                   //有歧义,编译器无法区分
    //--->解决办法,定义一个更加具体的 偏特化 CCC<int, int>
    // 偏特化的优先级:越具体的,优先级越高
    cout << "C1:" << C1 << endl;
    cout << "C2:" << C2 << endl;
    cout << "C3:" << C3 << endl;
    cout << "C4:" << C4 << endl;
    cout << "C5:" << C5 << endl;
}
int main()
{
    //TestTemplate();
    //TestBBB();
    //TestMax();
    TestSpecial();
    //system("pause");
  return 0;
}
相关文章
|
2月前
|
缓存 算法 程序员
C++STL底层原理:探秘标准模板库的内部机制
🌟蒋星熠Jaxonic带你深入STL底层:从容器内存管理到红黑树、哈希表,剖析迭代器、算法与分配器核心机制,揭秘C++标准库的高效设计哲学与性能优化实践。
C++STL底层原理:探秘标准模板库的内部机制
|
6月前
|
存储 算法 安全
c++模板进阶操作——非类型模板参数、模板的特化以及模板的分离编译
在 C++ 中,仿函数(Functor)是指重载了函数调用运算符()的对象。仿函数可以像普通函数一样被调用,但它们实际上是对象,可以携带状态并具有更多功能。与普通函数相比,仿函数具有更强的灵活性和可扩展性。仿函数通常通过定义一个包含operator()的类来实现。public:// 重载函数调用运算符Add add;// 创建 Add 类的对象// 使用仿函数return 0;
237 0
|
6月前
|
人工智能 机器人 编译器
c++模板初阶----函数模板与类模板
class 类模板名private://类内成员声明class Apublic:A(T val):a(val){}private:T a;return 0;运行结果:注意:类模板中的成员函数若是放在类外定义时,需要加模板参数列表。return 0;
190 0
|
10月前
|
存储 缓存 C++
C++ 容器全面剖析:掌握 STL 的奥秘,从入门到高效编程
C++ 标准模板库(STL)提供了一组功能强大的容器类,用于存储和操作数据集合。不同的容器具有独特的特性和应用场景,因此选择合适的容器对于程序的性能和代码的可读性至关重要。对于刚接触 C++ 的开发者来说,了解这些容器的基础知识以及它们的特点是迈向高效编程的重要一步。本文将详细介绍 C++ 常用的容器,包括序列容器(`std::vector`、`std::array`、`std::list`、`std::deque`)、关联容器(`std::set`、`std::map`)和无序容器(`std::unordered_set`、`std::unordered_map`),全面解析它们的特点、用法
C++ 容器全面剖析:掌握 STL 的奥秘,从入门到高效编程
|
9月前
|
编译器 C++
模板(C++)
本内容主要讲解了C++中的函数模板与类模板。函数模板是一个与类型无关的函数家族,使用时根据实参类型生成特定版本,其定义可用`typename`或`class`作为关键字。函数模板实例化分为隐式和显式,前者由编译器推导类型,后者手动指定类型。同时,非模板函数优先于同名模板函数调用,且模板函数不支持自动类型转换。类模板则通过在类名后加`&lt;&gt;`指定类型实例化,生成具体类。最后,语录鼓励大家继续努力,技术不断进步!
|
10月前
|
安全 C++
【c++】模板详解(2)
本文深入探讨了C++模板的高级特性,包括非类型模板参数、模板特化和模板分离编译。通过具体代码示例,详细讲解了非类型参数的应用场景及其限制,函数模板和类模板的特化方式,以及分离编译时可能出现的链接错误及解决方案。最后总结了模板的优点如提高代码复用性和类型安全,以及缺点如增加编译时间和代码复杂度。通过本文的学习,读者可以进一步加深对C++模板的理解并灵活应用于实际编程中。
158 0
|
10月前
|
存储 算法 C++
深入浅出 C++ STL:解锁高效编程的秘密武器
C++ 标准模板库(STL)是现代 C++ 的核心部分之一,为开发者提供了丰富的预定义数据结构和算法,极大地提升了编程效率和代码的可读性。理解和掌握 STL 对于 C++ 开发者来说至关重要。以下是对 STL 的详细介绍,涵盖其基础知识、发展历史、核心组件、重要性和学习方法。
|
10月前
|
存储 安全 算法
深入理解C++模板编程:从基础到进阶
在C++编程中,模板是实现泛型编程的关键工具。模板使得代码能够适用于不同的数据类型,极大地提升了代码复用性、灵活性和可维护性。本文将深入探讨模板编程的基础知识,包括函数模板和类模板的定义、使用、以及它们的实例化和匹配规则。
|
10月前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
6月前
|
存储 编译器 程序员
c++的类(附含explicit关键字,友元,内部类)
本文介绍了C++中类的核心概念与用法,涵盖封装、继承、多态三大特性。重点讲解了类的定义(`class`与`struct`)、访问限定符(`private`、`public`、`protected`)、类的作用域及成员函数的声明与定义分离。同时深入探讨了类的大小计算、`this`指针、默认成员函数(构造函数、析构函数、拷贝构造、赋值重载)以及运算符重载等内容。 文章还详细分析了`explicit`关键字的作用、静态成员(变量与函数)、友元(友元函数与友元类)的概念及其使用场景,并简要介绍了内部类的特性。
281 0