C++核心编程-类模板II

本文深入探讨了C++模板类的成员函数实现,包括类外实现和类内实现。讨论了在分文件编写时遇到的链接问题及其解决方案。接着介绍了类模板中的友元函数,包括全局函数作为友元的声明和实现。最后,通过一个通用的数组类实例,展示了类模板在实际编程中的应用,涵盖了构造函数、拷贝构造、赋值运算符重载、尾插法、下标访问以及析构函数等关键概念。
摘要由CSDN通过智能技术生成

1.类模板成员函数类外实现

#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();
    //类内实现
    // {
    //     cout<<this->m_Name<<this->m_Age<<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;
}
//成员函数的类外实现
template<class T1,class T2>
void Person<T1,T2>::showPerson(){
    cout<<this->m_Name<<this->m_Age<<endl;
}
void test01(){
    Person<string,int>P("TOM",18);
    P.showPerson();
}
int main(){
    test01();
}

2.类模板分文件编写

问题:类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到

解决:1.直接包含.cpp源文件;2.将声明和实现写在同一个文件中,并更改后缀为.hpp hpp是约定的名称,并不是强制

原因:类模板中成员函数开始的时候是没有创建的

3.类模板与友元

全局函数类内实现-直接在类内声明友元即可

全局函数类外实现-需要提前让编译器知道全局函数的存在

#include <iostream>
#include <string>
using namespace std;
template<class T1,class T2>
//提前让编译器知道Person类的存在
class Person;
//类外实现,提前让编译器知道它的存在
template<class T1,class T2>
void printPerson2(Person<T1,T2> p){
    cout<<p.m_Name<<p.m_Age<<endl;
}
//通过全局函数打印信息
template<class T1,class T2>
class Person{
public:
//全局函数类内实现
    friend void printPerson(Person<T1,T2> p){
        cout<<p.m_Name<<p.m_Age<<endl;
    }
//全局函数类外实现
//加一个空模板参数列表
//如果全局函数是类外实现,需要让编译器提前知道它的存在
    friend void printPerson2<>(Person<T1,T2> p);

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

void test01(){
    Person<string,int>P("Tom",30);
    printPerson2(P);
}
int main(){
    test01();
}

4.类模板案例  实现通用的数组类

注意!!

有参构造、拷贝构造(注意深浅拷贝的问题!这里的区别在代码里已经有所体现)、

=运算符重载(同样注意深浅拷贝的问题,以及函数调用想作为左值存在,返回该类型的引用

尾插法的实现、下标访问的实现、析构函数

#include <iostream>
#include <string>
using namespace std;
template<class T>
class MyArray{
public:
//有参构造 参数 容量
    MyArray(int capacity){
        //cout<<"有参构造调用"<<endl;
        this->m_Capacity=capacity;
        this->m_Size=0;
        this->pAddress=new T[this->m_Capacity];
    }
//拷贝构造
    MyArray(const MyArray& arr){
        //cout<<"拷贝构造调用"<<endl;
        this->m_Capacity=arr.m_Capacity;
        this->m_Size=arr.m_Size;
        //this->pAddress=arr.pAddress;浅拷贝
        this->pAddress=new T[arr.m_Capacity];//深拷贝
        //将arr中的数据都拷贝过来
        for(int i=0;i<this->m_Size;i++){
            this->pAddress[i]=arr.pAddress[i];
        }
    }
//operator=  防止浅拷贝问题
//函数调用想作为左值存在,返回该类型的引用
    MyArray& operator=(const MyArray& arr){
        //cout<<"operator=调用"<<endl;
        //先判断原来堆区是否有数据,如果有先释放
        if(this->pAddress!=NULL){
            delete[]this->pAddress;
            this->pAddress=NULL;
            this->m_Capacity=0;
            this->m_Size=0;
        }
        //深拷贝
        this->m_Capacity=arr.m_Capacity;
        this->m_Size=arr.m_Size;
        this->pAddress=new T[arr.m_Capacity];
        for(int i=0;i<this->m_Size;i++){
            this->pAddress[i]=arr.pAddress[i];
        }
        return *this;
    }
//尾插法
    void Push_Back(const T &val){
        //判断容量是否等于大小
        if(this->m_Capacity==this->m_Size)
            return;
        this->pAddress[this->m_Size]=val;//在数组末尾插入数据
        this->m_Size++;//更新数组大小
    }
//尾删法
    void Pop_Back(){
        //让用户访问不到最后一个元素,逻辑删除
        if(this->m_Size==0)
            return;
        this->m_Size--;
    }
//通过下标方式访问数组中的元素
//函数调用想作为左值存在,返回该类型的引用
    T& operator[](int index){
        return this->pAddress[index];
    }
//返回数组容量
    int getCapacity(){
        return this->m_Capacity;
    }
//返回数组大小
    int getSize(){
        return this->m_Size;
    }
//析构函数
    ~MyArray(){
        if(this->pAddress!=NULL){
            //cout<<"析构函数调用"<<endl;
            delete[]this->pAddress;
            this->pAddress=NULL;
        }
    }
private:
    T* pAddress;//指针指向堆区开辟的真实数组
    int m_Capacity;//数组容量
    int m_Size;//数组大小
};
void print(MyArray<int>&arr){
    for(int i=0;i<arr.getSize();i++){
        cout<<arr[i]<<" ";
    }
}
void test01(){
    MyArray<int>arr1(5);
    for(int i=0;i<5;i++){
        arr1.Push_Back(i);
    }
    print(arr1);
    arr1.Pop_Back();
    cout<<arr1.getCapacity()<<arr1.getSize()<<endl;
    // MyArray<int>arr2(arr1);
    // MyArray<int>arr3(100);
    // arr3=arr1;
}
//测试自定义数据类型
class Person{
public:
    Person(string name,int age){
        this->m_Name=name;
        this->m_Age=age;
    }
    string m_Name;
    int m_Age;
};
void PrintPerson(MyArray<Person>& arr){
    for(int i=0;i<arr.getSize();i++){
        cout<<arr[i].m_Name<<" "<<arr[i].m_Age;
    }
}
void test02(){
    MyArray<Person>arr2(10);
    Person p1("孙悟空",999);
    Person p2("韩信",33);
    Person p3("妲己",20);
    Person p4("赵云",15);
    Person p5("安其拉",9);
    arr2.Push_Back(p1);
    arr2.Push_Back(p2);
    arr2.Push_Back(p3);
    arr2.Push_Back(p4);
    arr2.Push_Back(p5);
    PrintPerson(arr2);
}
int main(){
    test02();
}

        

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值