首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >C++ 自定义数组类模板

C++ 自定义数组类模板

作者头像
用户6021899
发布2021-07-05 15:41:32
发布2021-07-05 15:41:32
1.4K00
代码可运行
举报
运行总次数:0
代码可运行

本篇通过自定义数组类模板,实现python列表的绝大部分函数,包括:

  1. 求最大值
  2. 求最小值
  3. 排序
  4. 在尾部添加元素
  5. 在指定位置(默认尾部)删除元素
  6. 在指定位置插入元素
  7. 在尾部添加进另外一个数组
  8. 查找指定值
  9. 移除第一次出现的指定值
  10. 从尾到头反向排列
  11. 切片功能
  12. 两个数组相等的判断
  13. 列表的数乘复制 等等

以及numpy中的arange函数

涉及到的知识点有:

  • 类模板
  • 函数模板
  • 友元函数模板的类外实现
  • 运算符重载(==, !=, *, +, <<, [])

头文件myArray.hpp代码如下:

代码语言:javascript
代码运行次数:0
运行
复制
#pragma once


#include <iostream>
using namespace std;


//因为 int len(MyArray<T>& arr) 在类定义之前,需要提前让编译器知道MyArray是一个类模板
template <class T>
class MyArray;


//友元函数模板类外实现,需要让编译器提前知道它的存在
template<class T>
int len(MyArray<T>& arr)
{
    return arr.m_length;
}


//友元函数模板类外实现,需要让编译器提前知道它的存在
//重载<<
template<class T>
ostream & operator<<(ostream& out, MyArray<T>& arr)
{
    cout<<'[';
    int j=1;
    if (len(arr)>0)
    {
        for(int i=0; i< arr.m_length-1; i++)
        {
            out<< arr.pAddress[i]<<",";
            //if(j%20==0) out<<endl;
            j++;
        }
        out<< arr.pAddress[arr.m_length-1];
    }
    cout<<']';
    return out;
}


template<class T>
ostream & operator<<(ostream& out, MyArray<T>&& arr)
{
    cout<<'[';
    int j=1;
    if (len(arr)>0)
    {
        for(int i=0; i< arr.m_length-1; i++)
        {
            out<< arr.pAddress[i]<<",";
            //if(j%20==0) out<<endl;
            j++;
        }
        out<< arr.pAddress[arr.m_length-1];
    }
    cout<<']';
    return out;
}


template<typename T>
MyArray<T>& arange(T start, T stop, T step)
{
    if(step >0)
    {
        if(start>= stop)
        {
            MyArray<T>* p = new MyArray<T>;
            return *p;
        }


        int n=0;
        T x = start;
        while(x < stop)
        {
            n++;
            x += step;
        }
        MyArray<T>* p = new MyArray<T>(n);
        p->m_length = n;
        for(int i=0; i<n; i++)
        {
            p->pAddress[i] = start + i*step;
        }
        return *p;


    }
    else if(step<0)
    {
        if(start<= stop)
        {
            MyArray<T>* p = new MyArray<T>;
            return *p;
        }


        int n=0;
        T x = start;
        while(x > stop)
        {
            n++;
            x += step;
        }
        MyArray<T>* p = new MyArray<T>(n);
        p->m_length = n;
        for(int i=0; i<n; i++)
        {
            p->pAddress[i] = start + i*step;
        }
        return *p;
    }
    else throw invalid_argument("step cannot be zero");
}


template <class T>
class MyArray
{
    friend int len<>(MyArray<T>& arr);//友元函数模板类外实现的类内声明,需要加空模板参数列表
    friend ostream & operator<<<>(ostream& out, MyArray<T>& arr);
    friend ostream & operator<<<>(ostream& out, MyArray<T>&& arr);
    friend MyArray<T>& arange<>(T start, T stop, T step);


public:
    MyArray(int length)
    {
        //cout <<"MyArray有参构造函数的调用"<<endl;
        //cout<<"T的实际类型是 "<<typeid(T).name()<<endl;
        if(length< 0) throw invalid_argument("length should not be negative");
        else if (length == 0) this->pAddress = NULL;
        else this->pAddress = new T[length];


        this->m_length = length;
    }


    MyArray()
    {
        //cout <<"MyArray无参构造函数的调用"<<endl;
        this->pAddress = NULL;
        this->m_length = 0;
    }


    MyArray(MyArray& arr)
    {
        //cout <<"MyArray拷贝构造函数的调用"<<endl;
        this->m_length = arr.m_length;
        this->pAddress = new T[this->m_length];//深拷贝
        for(int i=0; i< this->m_length; i++)//复制数组内容
        {
            this->pAddress[i] = arr.pAddress[i];
        }
    }


    //重载赋值操作符,防止浅拷贝问题
    MyArray& operator=(const MyArray& arr)
    {
        //cout<<"赋值操作符的重载"<<endl;
        //如果原来堆区有数据,需要先释放
        if(this->pAddress != NULL)
        {
            delete [] pAddress;
        }


        this->m_length = arr.m_length;
        this->pAddress = new T[arr.m_length];//深拷贝
        for(int i=0; i< this->m_length; i++)//复制数组内容
        {
            this->pAddress[i] = arr.pAddress[i];
        }
        return *this;


    }


    ~MyArray()
    {
        //cout <<"MyArray析构函数的调用"<<endl;
        if(this->pAddress != NULL)
        {
            delete [] this->pAddress;
            pAddress = NULL;
            this->m_length = 0;
        }
    }


    T& operator[](int index)//注意返回引用,否则不能当左值
    {
        //索引转换,负数索引转换到0 ~ length-1 区间


        if (0 <= index && index < this->m_length)
            return this->pAddress[index];
        else if (-this->m_length <= index && index < 0)
        {
            int index_;
            index_ = index + this->m_length;
            return this->pAddress[index_];
        }
        else throw invalid_argument("index out of range");
    }


    MyArray& sort(bool reversed=false)
    {


        //冒泡排序
        T* p = this->pAddress;
        T temp;
        if(reversed)
        {
            for(int i = 0; i < this->m_length; i++)
            {
                for(int j = 0; j < this->m_length -1 -i; j++)
                {


                    if(p[j] < p[j+1])
                    {
                        temp = p[j];
                        p[j] = p[j+1];
                        p[j+1] = temp;
                    }
                }
            }
        }
        else
        {
            for(int i = 0; i < this->m_length; i++)
            {
                for(int j = 0; j < this->m_length -1 -i; j++)
                {


                    if(p[j] > p[j+1])
                    {
                        temp = p[j];
                        p[j] = p[j+1];
                        p[j+1] = temp;
                    }
                }
            }
        }


        return *this;
    }


    T max()
    {
        T max_ = this->pAddress[0];
        for(int i = 1; i < this->m_length; i++)
        {
            if (this->pAddress[i] > max_) max_ = this->pAddress[i];
        }
        return max_;
    }


    T min()
    {
        T min_ = this->pAddress[0];
        for(int i = 1; i < this->m_length; i++)
        {
            if (this->pAddress[i] < min_) min_ = this->pAddress[i];
        }
        return min_;
    }


    int count(T value)
    {
        int qty = 0;
        for(int i = 0; i < this->m_length; i++)
        {
            if (value == this->pAddress[i]) qty++;
        }
        return qty;
    }


    void append(T value)
    {
        T* p = new T[this->m_length + 1];
        if(this->pAddress != NULL)
        {
            for(int i=0; i< this->m_length; i++)//复制原数组内容
            {
                p[i] = this->pAddress[i];
            }
            p[this->m_length] = value;
            delete [] this->pAddress;
            this->pAddress = p;
        }
        else
        {
            this->pAddress = new T[1];
            this->pAddress[0] = value;
        }
        this->m_length ++;
    }


    void insert(int index, T value)
    {
        //在index前插入值
        int index_;
        if (0 <= index && index < this->m_length)
            index_ = index;
        else if (-this->m_length <= index && index < 0)
            index_ = index + this->m_length;
        else throw invalid_argument("index out of range");


        T* p = new T[this->m_length + 1];
        for(int i=0; i<index_; i++)
            p[i] = this->pAddress[i];
        for(int i=index_; i< this->m_length; i++)
            p[i+1] = this->pAddress[i];


        p[index_] = value;
        this->pAddress = p;
        this->m_length++;


    }




    T pop(int index=-1)
    {
        if(this->pAddress == NULL)
            throw invalid_argument("No element in array");


        int index_;
        if (0 <= index && index < this->m_length)
            index_ = index;
        else if (-this->m_length <= index && index < 0)
            index_ = index + this->m_length;
        else throw invalid_argument("index out of range");


        T temp = this->pAddress[index_];
        T* p = new T[this->m_length - 1];
        for(int i=0; i<index_; i++)
            p[i] = this->pAddress[i];
        for(int i=index_+1; i< this->m_length; i++)
            p[i-1] = this->pAddress[i];
        this->pAddress = p;
        this->m_length--;


        if(this->m_length==0)
        {
            delete[] this->pAddress;
            this->pAddress = NULL;
        }


        return temp;
    }


    void remove(T value)
    {
        //移除第一次出现的值,若不存在则抛出异常
        if(this->pAddress == NULL)
            throw invalid_argument("No element in array");


        int i;
        for(i=0; i < this->m_length; i++)
        {
            if(value == this->pAddress[i]) break;
        }


        if(i == this->m_length)
            throw invalid_argument("not found");


        T* p = new T[this->m_length - 1];
        for(int j=0; j<i; j++)
            p[j] = this->pAddress[j];
        for(int j=i+1; j< this->m_length; j++)
            p[j-1] = this->pAddress[j];
        this->pAddress = p;
        this->m_length--;
        if(this->m_length==0)
        {
            delete[] this->pAddress;
            this->pAddress = NULL;
        }


    }


    void extend(MyArray& arr)
    {
        int total_length = this->m_length + arr.m_length;
        T* p = new T[total_length];
        if(this->pAddress != NULL)
        {
            for(int i=0; i< this->m_length; i++)//复制原数组内容
            {
                p[i] = this->pAddress[i];
            }
            for(int i=0; i< arr.m_length; i++)//复制待添加的数组内容
            {
                p[this->m_length + i] = arr.pAddress[i];
            }


            delete [] this->pAddress;
            this->pAddress = p;
        }
        else
        {
            this->pAddress = new T[arr.m_length];
            for(int i=0; i< arr.m_length; i++)//复制待添加的数组内容
            {
                this->pAddress[i] = arr.pAddress[i];
            }
        }
        this->m_length = total_length;


    }


    int index(T value, int start=0, int stop=-1)
    {


        //在start和stop之间,找出value第一次出现的index
        if(this->pAddress == NULL)
            throw invalid_argument("No element in array");


        int start_;
        if (0 <= start && start < this->m_length)
            start_ = start;
        else if (-this->m_length <= start && start < 0)
            start_ = start + this->m_length;
        else throw invalid_argument("start out of range");


        int stop_;
        if (0 <= stop && stop < this->m_length)
            stop_ = stop;
        else if (-this->m_length <= stop && stop < 0)
            stop_ = stop + this->m_length;
        else throw invalid_argument("stop out of range");


        if(start_ >= stop_)
            throw invalid_argument("start_ should be less than stop_");


        for(int i = start_; i <= stop_; i++)
        {
            if(value == this->pAddress[i]) return i;
        }


        throw invalid_argument("not found");




    }


    MyArray& reverse()
    {
        if(this->pAddress!= NULL)
        {
            T temp;
            int mirrored;
            for(int i=0; i< this->m_length / 2; i++)
            {
                mirrored = this->m_length-1 - i;
                temp = this->pAddress[i];
                this->pAddress[i] = this->pAddress[mirrored];
                this->pAddress[mirrored] = temp;
            }
        }
        return *this;
    }




    bool operator==(MyArray& arr)
    {
        if (this->m_length != arr.m_length) return false;
        for(int i; i < arr.m_length; i++)
        {
            if(this->pAddress[i] != arr.pAddress[i]) return false;
        }
        return true;
    }


    bool operator!=(MyArray& arr)
    {
        if (this->m_length != arr.m_length) return true;
        for(int i; i < arr.m_length; i++)
        {
            if(this->pAddress[i] != arr.pAddress[i]) return true;
        }
        return false;
    }




    MyArray operator+(MyArray& arr)
    {
        int total_length = this->m_length + arr.m_length;
        MyArray<T> sum(total_length);
        for(int i=0; i< this->m_length; i++)//复制原数组内容
        {
            sum.pAddress[i] = this->pAddress[i];
        }
        for(int i=0; i< arr.m_length; i++)//复制待添加的数组内容
        {
            sum.pAddress[this->m_length + i] = arr.pAddress[i];
        }
        return sum;
    }


    MyArray operator*(int n)
    {
        if(n <0) throw invalid_argument("n should not be negative");
        if (n==0)
        {
            MyArray<T> sum;
            return sum;
        }


        int total_length = this->m_length * n;
        MyArray<T> sum(total_length);
        for(int k=0; k < n; k++)
        {
            for(int i=0; i< this->m_length; i++)//复制原数组内容
            {
                sum.pAddress[k* this->m_length + i] = this->pAddress[i];
            }
        }


        return sum;
    }


    int convert_index(int index)
    {
        //索引转换,负数或者越界的索引转换到0 ~ length 区间
        if (index <= -this->m_length) return 0;
        else if (index < 0) return this->m_length + index;
        else if(index < this->m_length) return index;
        else return this->m_length;
    }


    MyArray sliced(int start, int end, int step)
    {
        if (step>0)
        {
            int start_, end_, n_sliced, r ;
            start_ = this->convert_index(start);
            end_ = this->convert_index(end);
            if(start_ >= end_)
            {
                MyArray<T> nothing;
                return nothing;
            }


            r = (end_ - start_) % step;
            if(r==0) n_sliced = (end_ - start_)/ step;
            else n_sliced = (end_ - start_)/ step + 1;


            MyArray<T> sliced(n_sliced);
            for(int i=0; i<n_sliced; i++)
            {
                int index_ = start_ + i * step;
                sliced.pAddress[i] = this->pAddress[index_];
            }
            return sliced;
        }


        else if (step<0)
        {
            int start_, end_, n_sliced, r ;
            start_ = this->convert_index(start);
            end_ = this->convert_index(end);
            if (start_ == this->m_length) start_--;


            if(start_ <= end_)
            {
                MyArray<T> nothing;
                return nothing;
            }


            r = (start_ - end_) % (-step);
            if(r==0) n_sliced = (start_ - end_) / (-step);
            else n_sliced = (start_ - end_) / (-step) + 1;


            MyArray<T> sliced(n_sliced);
            for(int i=0; i < n_sliced; i++)
            {
                int index_ = start_ + i * step;
                sliced.pAddress[i] = this->pAddress[index_];
            }
            return sliced;
        }


        else  throw invalid_argument("slice step cannot be zero");


    }




private:
    T* pAddress;//指向堆区开辟的数组
    int m_length;//数组元素个数


};

测试用的代码如下:

代码语言:javascript
代码运行次数:0
运行
复制
#include<iostream>
#include <time.h>
#include "myArray.hpp"




void test1()
{
    MyArray<float> a1(5);
    MyArray<float> a2(a1);
    MyArray<float> a3 = a1;//这步不会调用operator==,而是调用拷贝构造
    MyArray<float> a4(9);
    a4 = a1; //这步调用operator=
    cout<<"a4==a1:"<< ((a4 == a1)? "true":"false")<<endl;//注意括号提高优先级
    cout<<"a2!=a1:"<< ((a2 != a1)? "true":"false")<<endl;//注意括号提高优先级
    cout<<true<<endl;
    srand(time(0));//设置随时间变化的随机种子
    for(int i=0; i < len(a1); i++)
    {
        a1[i] = rand()%11; //这步调用operator[]
    }
    cout<<"排序前:"<<endl;
    cout<<a1<<endl;
    cout <<"max element of a1 = "<< a1.max()<<endl;
    cout <<"min element of a1 = "<< a1.min()<<endl;


    cout<<"count of 1 in a1 = "<< a1.count(1)<<endl;


    a1.sort();
    cout<<endl;
    cout<<"排序后:"<<endl;
    cout<<a1<<endl;


    cout<<endl;
    a1.append(999.999);
    a1.insert(1,999.999);
    a1.insert(-1,888.0);
    a1.remove(999.999);
    a1.remove(999.999);




    for(int i=0; i < len(a4); i++)
    {
        a4[i] = i; //这步调用operator[]
    }
    a1.extend(a4);
    a1.extend(a1);
    cout<<a1<<endl;


    cout<<"length of a1 = "<< len(a1)<<endl;
    cout<<"a1[-1] = "<< a1[-1]<<endl;
    cout<<"a1[-22] = "<< a1[-22]<<endl;
    cout<<a1.pop()<<endl;
    cout<<a1.pop(-2)<<endl;
    cout<<a1.pop(0)<<endl;
    cout<<"开始打印:"<<endl;
    cout<<a1<<endl;
    cout<<"a1.index(1): "<<a1.index(1)<<endl;
    cout<<"a1.index(1,1,-1): "<<a1.index(1,2,-1)<<endl;


    a1.reverse();
    cout<<"逆转后:"<<endl;
    cout<<a1<<endl;


}
void index_test()
{
    MyArray<char> a(6);
    a[-1]='f';
    a[-2] = 'e';
    a[0]= 'a';
    a[1]= 'b';
    a[2]= 'c';
    a[3]= 'd';
    cout<<a<<endl;
}


void pop_test()
{
    MyArray<int> a(10);
    for(int i=0; i < len(a); i++)
    {
        a[i]=i;
    }
    cout<<a<<endl;
    cout<<len(a)<<endl;
    for(int i=0; i < 10; i++)
    {
        a.pop();


        cout<<len(a)<<","<<a<<endl;
    }


    MyArray<int> b(10);
    for(int i=0; i < len(b); i++)
    {
        b[i]=i;
    }
    for(int i=0; i < 10; i++)
    {
        b.pop(0);


        cout<<len(b)<<","<<b<<endl;
    }
    //cout<<a.index(0)<<endl;
}


void add_test()
{
    MyArray<int> a(5);
    for(int i=0; i < len(a); i++)
    {
        a[i]=i;
    }
    MyArray<int> x;
    x = a + a + a;
    cout <<x<<endl;


    MyArray<int> b;
    x = b + b;
    cout <<x<<endl;
}
void multiply_test()
{
    MyArray<int> a(6);
    for(int i=0; i < len(a); i++)
    {
        a[i]=i;
    }
    MyArray<int> b;
    MyArray<int> x;


    x = a * 0;
    cout <<x<<endl;


    x = a * 4;
    cout <<x<<endl;


    x = b * 2;
    cout <<x<<endl;
}


void slice_test()
{
    MyArray<int> a(100);
    for(int i=0; i < len(a); i++)
    {
        a[i]=i;
    }
    cout<<a<<endl;
    cout<<a.sliced(-1,1,-3)<<endl;
}


void arange_test()
{
    cout<<arange(0.0,10.01,0.2)<<endl;
    cout<<arange<float>(0,10,0.2)<<endl;
    cout<<arange(9.1,-1.0,-0.2)<<endl;
    cout<<arange(0,20,2)<<endl;
    //cout<<arange(0,20,0)<<endl;//Exception raised due to zero step
}


int main()
{
    index_test();
    pop_test();
    add_test();
    multiply_test();
    slice_test();
    arange_test();


    return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-06-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python可视化编程机器学习OpenCV 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档