C++模板(二)-类模板

1. 类模板基本概念

类模板和函数模板的定义和使用类似,我们已经进行了介绍。有时,有两个或多个类,其功能是相同的,仅仅是数据类型不同。

类模板用于实现类所需数据的类型参数化

类模板在表示如数组、表、图等数据结构显得特别重要,这些数据结构的表示和算法不受所包含的数据类型的影响。

//类模板
template<class NameType,class AgeType>
class Person{
public:
    Person(NameType name, AgeType age){
       this->mName = name;
       this->mAge = age;
    }
    void PrintPerson(){
       cout << "Name:" << this->mName << " Age:" << this->mAge << endl;
    }
public:
    NameType mName;
    AgeType mAge;
};
 
void test05(){
 
    //记住:类模板只能显式指定类型,不能自动类型推导
    Person<string, int> p("John",30);
    p.PrintPerson();
}

2. 类模板做函数参数

//类模板
template<class NameType, class AgeType>
class Person{
public:
    Person(NameType name, AgeType age){
       this->mName = name;
       this->mAge = age;
    }
    void PrintPerson(){
       cout << "Name:" << this->mName << " Age:" << this->mAge << endl;
    }
public:
    NameType mName;
    AgeType mAge;
};
 
//类模板做函数参数
void DoBussiness(Person<string,int>& p){
    p.mAge += 20;
    p.mName += "_vip";
    p.PrintPerson();
}
 
int main(){
 
    Person<string, int> p("John", 30);
    DoBussiness(p);
 
    system("pause");
    return EXIT_SUCCESS;
}

3.  类模板派生普通类

//类模板
template<class T>
class MyClass{
public:
    MyClass(T property){
       this->mProperty = property;
    }
public:
    T mProperty;
};
 
//子类实例化的时候需要具体化的父类,子类需要知道父类的具体类型是什么样的
//这样c++编译器才能知道给子类分配多少内存
 
//普通派生类
class SubClass : public MyClass<int>{
public:
    SubClass(int b) : MyClass<int>(20){
       this->mB = b;
    }
public:
    int mB;
};

4.  类模板派生类模板

//父类类模板
template<class T>
class MyClass{
public:
    MyClass(T property){
       this->mProperty = property;
    }
public:
    T mProperty;
};
 
//子类类模板
template<class T>
class SubClass : public MyClass<T>{
public:
    SubClass(T b) : MyClass<T>(b){
       this->mB = b;
    }
public:
    T mB;
};

5. 类模板类内实现

//类模板类内实现  函数体在类模板的内部实现
template<class T>
class Person{
public:
    //重载左移操作符
    friend ostream& operator<<(ostream& out, Person& p){
       out << p.mProperty << endl;
       return out;
    }
    //重载普通友元
    friend void FriendPerson(Person& p){
       cout << p.mProperty << endl;
    }
    Person(T property){
       this->mProperty = property;
    }
    void PrintPerson(){
       cout << this->mProperty << endl;
    }
private:
    T mProperty;
};
 
void test(){
    Person<int> p(10);
    //调用类的成员函数打印
    p.PrintPerson();
    //重载左移操作符友元函数
    cout << p;
    //普通友元函数
    FriendPerson(p);
}

6.  类模板类外实现

//类模板类内实现  函数体在类模板的内部实现
template<class T>
class Person{
public:
    //重载左移操作符
    template<class T1> friend ostream& operator<<(ostream& out, Person<T1>& p);
    //重载普通友元
    template<class T2> friend void FriendPerson(Person<T2>& p);
    //构造函数
    Person(T property);
    //成员函数
    void PrintPerson();
private:
    T mProperty;
};
 
//----------类外实现--------------------
 
template<class T>
Person<T>::Person(T property){
    this->mProperty = property;
}
 
template<class T>
void Person<T>::PrintPerson(){
    cout << this->mProperty << endl;
}
 
//重载左移操作符
template<class T>
ostream& operator<<(ostream& out, Person<T>& p){
    out << p.mProperty << endl;
    return out;
}
 
//重载普通友元
template<class T>
void FriendPerson(Person<T>& p){
    cout << p.mProperty << endl;
}
 
int main(){
 
    //编译通过,那么咱们来用用
    Person<int> p(10);
    //调用成员方法编译通过执行通过
    p.PrintPerson();
    //调用普通友元函数编译报错无法解析的外部符号
    FriendPerson(p);
    //调用重载左移操作符编译报错无法解析的外部符号
    cout << p;
 
    system("pause");
    return EXIT_SUCCESS;
}

7. 类模板头文件和源文件分离问题

Person.h

#ifndef PERSON_H
#define PERSON_H
 
template<class T>
class Person{
public:
#if 1
    //重载左移操作符
    template<class T1> friend ostream& operator<<(ostream& out, Person<T1>& p);
    //重载普通友元
    template<class T2> friend void FriendPerson(Person<T2>& p);
#endif
    //构造函数
    Person(T property);
    //成员函数
    void PrintPerson();
private:
    T mProperty;
};
 
#endif

Person.cpp

#include "Person.h"
 
template<class T>
Person<T>::Person(T property){
    this->mProperty = property;
}
 
template<class T>
void Person<T>::PrintPerson(){
    cout << this->mProperty << endl;
}
 
#if 1
 
//重载左移操作符
template<class T>
ostream& operator<<(ostream& out, Person<T>& p){
    out << p.mProperty << endl;
    return out;
}
 
//重载普通友元
template<class T>
void FriendPerson(Person<T>& p){
    cout << p.mProperty << endl;
}
 
#endif

结论: 编译失败,无法链接的外部符号。

解决方案: 类模板的声明和实现放到一个文件中,我们把这个文件命名为.hpp(这个是个约定的规则,并不是标准,必须这么写).

原因:类模板需要二次编译,在出现模板的地方编译一次,在调用模板的地方再次编译。C++编译规则为独立编译。

8. 类模板碰到友元

8.1 类模板碰到普通友元函数

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;
 
//声明类模板存在
template<class T> class MyClass;
//声明友元函数模板存在
template<class T> void PrintMyClass(MyClass<T> &ms);
template<class T> ostream &operator<<(ostream &out, MyClass<T> &ms);
 
template<class T>
class MyClass{
   //普通友元函数必须提前声明
   friend void PrintMyClass<>(MyClass<T> &ms);
   //左移操作符(vs)不需要提前声明,(bcc gcc编译器需要提前声明)
   friend ostream &operator<<<>(ostream &out, MyClass<T> &ms);
public:
   MyClass();
private:
   T mA;
};
 
template<class T>
MyClass<T>::MyClass(){
   mA = 100;
}
 
template<class T>
void PrintMyClass(MyClass<T> &ms){
   cout << ms.mA << endl; //可访问
}
 
template<class T>
ostream &operator<<(ostream &out, MyClass<T> &ms){
   out << ms.mA;
   return out;
}
 
int main(){
 
   MyClass<int> ms;
   PrintMyClass(ms);
   cout << ms << endl;
 
   return 0;
}

8.2 类模板碰到友元函数模板

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
 
 
template<class T>
class MyClass{
   //友元函数模板
   template<class D> friend void PrintMyClass(MyClass<D> &ms);
   template<class D> friend ostream &operator<<(ostream &out, MyClass<D> &ms);
public:
   MyClass();
private:
   T mA;
};
 
template<class T>
MyClass<T>::MyClass(){
   mA = 100;
}
 
template<class T>
void PrintMyClass(MyClass<T> &ms){
   cout << ms.mA << endl; //可访问
}
 
template<class T>
ostream &operator<<(ostream &out, MyClass<T> &ms){
   out << ms.mA;
   return out;
}
 
int main(){
 
   MyClass<int> ms;
   PrintMyClass(ms);
   cout << ms << endl;
 
   system("pause");
   return EXIT_SUCCESS;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值