本文为学习黑马程序员C++模板时所作笔记,主要记录一些重点,更详细参见视频: Sir, this way

函数模板

 直接上代码举个栗子:

#include <iostream>

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

template<typename t>
void mysort(t arr[], int len)
{
    for (int i = 0; i <= len; i++)
    {
        int max = i;
        for (int j = i + 1; j <= len; j++)
        {
            if (arr[j] > arr[max])
            {
                max = j;
            }
        }
        if (max != i)
        {
            myswap(arr[max],arr[i]);
        }
    }
}

template<typename t>
void print(t arr[], int len)
{
    for (int i = 0; i < len; i++)
    {
        std::cout << arr[i]<<" ";
    }
    std::cout << std::endl;
}
int main(void)
{
    /*int a = 5, b = 10;
    double c = 6.6, d = 9.9;
    myswap(a, b);
    myswap(c, d);
    std::cout << "a:" << a << std::endl;
    std::cout << "b:" << b << std::endl;
    std::cout << "c:" << c << std::endl;
    std::cout << "d:" << d << std::endl;*/
    char a[] = "adwascf";
    int len = sizeof(a) / sizeof(char);
    mysort(a, len);
    print(a, len);

    int b[] = {1,5,9,6,4,2,7};
    int len_ = sizeof(b) / sizeof(int);
    mysort(b, len_);
    print(b, len_);
    return 0;
}

 

类模板

继续上代码:

#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>
#include <stdexcept>

using namespace std;

template <class T>
class Stack {
private:
    vector<T> elems;     // 元素 

public:
    void push(T const&);  // 入栈
    void pop();               // 出栈
    T top() const;            // 返回栈顶元素
    bool empty() const {       // 如果为空则返回真。
        return elems.empty();
    }
};

template <class T>
void Stack<T>::push(T const& elem)
{
    // 追加传入元素的副本
    elems.push_back(elem);
}

template <class T>
void Stack<T>::pop()
{
    if (elems.empty()) {
        throw out_of_range("Stack<>::pop(): empty stack");
    }
    // 删除最后一个元素
    elems.pop_back();
}

template <class T>
T Stack<T>::top() const
{
    if (elems.empty()) {
        throw out_of_range("Stack<>::top(): empty stack");
    }
    // 返回最后一个元素的副本 
    return elems.back();
}

int main()
{
    try {
        Stack<int>         intStack;  // int 类型的栈 
        Stack<string> stringStack;    // string 类型的栈 

        // 操作 int 类型的栈 
        intStack.push(7);
        cout << intStack.top() << endl;

        // 操作 string 类型的栈 
        stringStack.push("hello");
        cout << stringStack.top() << std::endl;
        stringStack.pop();
        stringStack.pop();
    }
    catch (exception const& ex) {
        cerr << "Exception: " << ex.what() << endl;
        return -1;
    }
}

类模板与函数模板区别

1.函数模板可以自动类型转换,而类模板必须指明

2.类模板可以有默认参数

3.类模板中的成员方法,在调用时才会去生成(因此在分文件编写时会出错,有两种解决方案:

1.不能用".h"而是".cpp",即先让编译器看源文件

2.将.h和.cpp中的内容写在一起,创建一个".hpp"(约定俗成,指模板文件)的文件)

 
 

类模板实例化对象作参数传递给函数

 

#include< iostream>
#include<string>
//using namespace std;
template<class T1, class T2>
class Person{
public:
    Person(T1 name, T2 age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }
    void showPerson()
    {
        std::cout << "姓名:" << this->m_Name << "  年龄:" << this->m_Age << std::endl;
    }
    T1 m_Name;
    T2 m_Age;
};

//直接指定
void printPerson_1(Person<std::string,int> &p)
{
    p.showPerson();
}

void test01()
{
    Person<std::string, int> p("孙悟空", 99);
    printPerson_1(p);
}

//参数模板化
template<class T1, class T2>
void printPerson_2(Person<T1, T2>& p)
{
    p.showPerson();
    std::cout << "T1的类型为:" << typeid(T1).name() << std::endl;
    std::cout << "T2的类型为:" << typeid(T2).name() << std::endl;
}

void test02()
{
    Person<std::string, int> p("猪八戒", 90);
    printPerson_2(p);
}


//整个类模板化
template<class T>
void printPerson_3(T &p)
{
    p.showPerson();
    std::cout << "T的类型为:" << typeid(T).name() << std::endl;
}

void test03()
{
    Person<std::string, int> p("唐僧", 30);
    printPerson_3(p);
}

int main(void)
{
    test01();
    test02();
    test03();
    return 0;
}

 使用较多的还是第一种:直接指定

 

类模板的继承问题

#include<iostream>

template<class T>
class Base {
    T m;
};

//class Son:public Base { 报错!只有知道父类中T的类型,才能继承给子类
class Son1:public Base<int>{

};

void test01()
{
    Son1 s1;
}


//如果想让子类灵活继承父类中T类型,那子类也需要变成类模板
template<class T1, class T2>
class Son2 :public Base<T2> {
    T1 obj;
public:
    Son2()
    {
        std::cout << "T1的类型为:" << typeid(T1).name() << std::endl;
        std::cout << "T2的类型为:" << typeid(T2).name() << std::endl;
    }
};

void test02()
{
    Son2<int, char> s2;
}
int main(void)
{
    test01();
    test02();
    return 0;
}

本质上是子类继承是类模板的基类,需要子类自己指定T的数据类型

 

类模板函数类外实现

#include<iostream>
#include<string>

template<class T1, class T2>
class Person {
public:
    Person(T1 name, T2 age);
    void showPerson()
    {
        std::cout << "姓名:" << this->m_Name << "  年龄:" << this->m_Age << std::endl;
    }
    T1 m_Name;
    T2 m_Age;
};

template<class T1, class T2>
Person<T1,T2>::Person(T1 name, T2 age)
{
    this->m_Name = name;
    this->m_Age = age;
}

void test()
{
    Person<std::string, int> p("Tom", 99);
    p.showPerson();
}

int main(void)
{
    test();
    return 0;
}

类外实现需要将实现定义为函数模板,并且指明类型!

 

类模板和友元

#include<iostream>
#include<string>
//通过全局函数来打印Person信息
//让编译器提前知道类外实现,而且还要在此基础上提前让它知道Person类!
template<class T1, class T2>
class Person;

template<class T1, class T2>
void printPerson_2(Person<T1, T2>p)
{
    std::cout << "类外实现------姓名:" << p.m_Name << "  年龄:" << p.m_Age << std::endl;
}
template<class T1, class T2>
class Person {
public:
    Person(T1 name, T2 age)
    {
        this->m_Name = name;
        this->m_Age = age;
    }

    //全局函数类内实现
    friend void printPerson_1(Person<T1,T2>p)
    {
        std::cout << "类内实现------姓名:" << p.m_Name << "  年龄:" << p.m_Age << std::endl;
    }

    //全局函数类外实现
    friend void printPerson_2<>(Person<T1, T2>p);//需要多加一个"<>"空模板参数列表 指明这是一个类外实现!
private:
    T1 m_Name;
    T2 m_Age;
};

//类外的实现在下方会链接出错!这需要让编译器提前知道(因为成了模板)
//template<class T1, class T2>
//void printPerson_2(Person<T1, T2>p)
//{
//    std::cout << "类外实现------姓名:" << p.m_Name << "  年龄:" << p.m_Age << std::endl;
//}

void test01()
{
    Person<std::string, int> p("Tom", 99);
    printPerson_1(p);
}

void test02()
{
    Person<std::string, int> p("Jerry", 88);
    printPerson_2(p);
}

int main(void)
{
    test01();
    test02();
}

友元的类外实现还是不太容易的,需要让编译器提前知道,定义也要有变化(笔者写容器的迭代器用到类中类时,遇到过这个问题)

posted on 2022-05-27 11:58  DrizzleDrop  阅读(52)  评论(0编辑  收藏  举报