C++ 泛型编程(GP)类模板

目录

1类模板(语法规则)

2对象的创建

3类模板做函数参数

4类模板分文件编写

5类模板的继承问题

6友元

7应用


1类模板(语法规则)

template<class T1,class T2>
class className{
public:
   T1 arg1;
   T2 arg2;
   //....
};
template<class T1,class T2>
class Person{
private:
    T1 names;
    T2 age;
public:
    Person(T1 name,T2 age);
};
template<class T1,class T2>
Person<T1,T2>::Person(T1 name,T2 age){
    this->names = name;
    this->age = age;
}

务必要注意模板类的作用域范围。

在类外进行实现的时候,需要针对类的作用域继续声明:

Person<T1,T2>

2对象的创建

隐式创建

Person<int,QString> p1(12,"name");

需要声明参数的具体类型

3类模板做函数参数

现在有类Person

template<class T1,class T2>
class Person{
public:
    Person(T1 name,T2 age);
    T1 name;
    T2 age;
};

一共有三种方式,来使用类模板做参数

//指定传入类型
void doWork(Person<QString,int> & p){
    qDebug()<<"指定传入类型:"<<"Person object's name"<<p.name<<" Person object's age"<<p.age;
    //....
}
//参数模板化
template<class T1,class T2>
void doWork2(Person<T1,T2> & p){
    qDebug()<<"参数模板化:"<<"Person object's name"<<p.name<<" Person object's age"<<p.age;
    //....
}
//整体类型化
template<class T>
void doWork3(T & p){
    qDebug()<<"参整体类型化:"<<"Person object's name"<<p.name<<" Person object's age"<<p.age;
    //....
}

 三种方式,逐渐抽象

示例1:

    Person<QString,int> p("name",12);
    doWork(p);
    doWork2(p);
    doWork3(p);

输出:

示例2:

    Person<int,QString> p2(12,"name");
    doWork2(p2);
    doWork3(p2);

输出:

从示例中可以看到,dowork3其实并不知道参数是什么具体类型,但是编译过程中并没有报错,只要调用的时候传入了正确的参数,依旧是可以完美执行的,关于模板函数的创建时间,可以理解为运行时绑定。

4类模板分文件编写

因为类模板函数是在运行时绑定的,如果在Person.h中声明相关变量及函数,在Person.cpp中进行实现。

那么,如果要使用类模板的各类接口,例如在client.cpp中调用,仅仅包含Person.h是不够的(会报错,表示接口未定义,因为具体的实现是要在运行时才绑定,编译时并不会将声明和实现结合),是要包含Peron.cpp的。

一般很少这么写,解决方法,就是全部写在.h中,类内声明,类外实现,并将.h改名为.hpp。

//.hpp
template<class T1,class T2>
class Person{
    T1 name;
    T2 age;
public:
    Person(T1 name,T2 age);

    void showItem();
};

template<class T1,class T2>
Person<T1,T2>::Person(T1 name,T2 age){
    this->name = name;
    this->age = age;
}
template<class T1,class T2>
void Person<T1,T2>::showItem(){
    qDebug()<<"name:"<<name<<"age:"<<age;
}

5类模板的继承问题

子类继承于类模板,必须指定类模板的具体类型

固定类型:

template<class T1,class T2>
class Person{
    T1 name;
    T2 age;
public:
    Person(T1 name,T2 age);

    void showItem();
};

//继承时必须指定类型,否则无法分配空间
class B :public Person<QString,int>{

};

灵活类型:

template<class T1,class T2>

class C : public Person<T2>{
    T1 item;
};

//.......
C<int,double> c;
//其中,父类的具体类型为double,而item类型为int

6友元

template<class T1,class T2>
class Person{
private:
    T1 name;
    T2 age;
    friend void printPerson(Person<QString,int> & p){
        qDebug()<<"姓名:"<<p.name<<"年级:"<<p.age;
    }
public:
    //...
};

7应用

编写一个数组

#include <QWidget>
template<class T>
class myArray
{
public: 
    //构造函数
    explicit myArray(int capacity){
        this->m_Capacity = capacity;
        this->m_Size = 0;
        this->pAddress = new T[capacity];
    }
    //构造函数
    myArray(const myArray & array){
        this->m_Capacity = array.m_Capacity;
        this->m_Size = array.m_Size;
        this->pAddress = new T[array.m_Capacity];
        for(int i= 0;i<this->m_Size;++i){
            this->pAddress[i] = array[i];
        }
    }
    //析构函数
    ~myArray(){
        if(this->pAddress != nullptr){
            delete this->pAddress;
            this->pAddress = nullptr;
        }
    }
    //等号重载
    myArray & operator =(myArray & array){
        //
        if(this->pAddress != nullptr){
            delete this->pAddress;
            this->pAddress = nullptr;
        }
        this->m_Capacity = array.m_Capacity;
        this->m_Size = array.m_Size;
        this->pAddress = new T[array.m_Capacity];
        for(int i= 0;i<this->m_Size;++i){
            this->pAddress[i] = array[i];
        }
    }
    //访问重载
    T & operator[](const int index){
        return this->pAddress[index];
    }
    //尾插
    void push_back(const T & value){
        this->pAddress[this->m_Size++] = value;
    }
    //获取数组大小
    int getSize(){
        return this->m_Size;
    }
    //获取数组容量
    int getCapacity(){
        return this->m_Capacity;
    }
private:
    int m_Size;
    int m_Capacity;
    T * pAddress;
};

应用情况:

    myArray<int> arr(100);
    for(int i= 0;i<10;++i){
        arr.push_back(i+1);
    }
    qDebug()<<arr.getCapacity()<<arr.getSize();
    for(int i = 0;i<10;++i){
        qDebug()<<arr[i];
    }

输出:

可以创建任意类型的数组,STL的底层也是这样实现的

    myArray<QString> arr(100);
    for(int i= 0;i<10;++i){
        QString val = QString::number(i+1);
        arr.push_back(val);
    }
    qDebug()<<arr.getCapacity()<<arr.getSize();
    for(int i = 0;i<10;++i){
        qDebug()<<arr[i];
    }

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值