C++运算符重载(五)

       C++允许在自己的类中,或是在全局作用域中重定义运算符的含义。由于很多面向对象的语言没有提供这种能力,因此你可能会低估这种特性在C++中的作用。C++中运算符的概念十分广泛,甚至包含[](数组索引)、()(函数调用)、类型转换以及内存分配和释放例程。可以通过运算符重载来改变语言运算符对自定义类的行为。能让自己的类具有内建类型的类似行为,甚至可以编写看上去类似于数组、函数或指针的类。在博主的《C++运算符重载》系列博文中会对我们常用的运算符提供重载的实例,希望大家能有所收获。额,本篇博文就让我们一起来探讨一下重载运算符中的下标访问运算符重载吧。

       一说到下标访问就很容易让人联想到数组,我们可以通过下标很方便的访问数组中的任意合法元素。博主在这里先暂时假设你从来没有听说过STL,更不知道vector和array类模板。博主将在这里封装一个简单的动态数组类模板,这个类允许设置和获取指定索引位置的元素,并会自动完成所有的内存分配操作。废话就不多说了,咱们直接上代码吧。当然,如果你是高手就可以略过啦^^。

//MyArray.h

#pragma once

#include <iostream>

using namespacestd;

 

template <typenameT>

class MyArray

{

public:

    MyArray(size_t size/* = 0*/);

    virtual~MyArray();

 

    //禁用拷贝构造函数和复制赋值运算符

    MyArray(constMyArray<T>&rhs) = delete;

    MyArray<T>&operator = (const MyArray<T> &rhs) = delete;

 

    //禁用自增和自减运算符(由于数组名是常量,不能修改)

    MyArray<T>&operator ++ () = delete;

    MyArray<T>&operator -- () = delete;

    MyArray<T>operator ++ (int) = delete;

    MyArray<T>operator -- (int) = delete;

 

    //重载下标访问运算符

    T& operator [] (size_tindex);

    constT& operator [] (size_tindex) const;

 

    //重载“+”运算符,方便通过数组名访问数组中所有元素

    T* operator + (rsize_tindex);

    constT* operator + (rsize_tindex) const;

 

    //重载解除引用运算符,以便通过数组名访问数组中的第一个元素

    T operator * ();

    constT operator * () const;

   

    //获取数组尺寸

    rsize_t getSize() const;

 

    //输出数组中所有元素值

    voidshow() const;

 

private:

 

    //当数组空间不够时,为数组再开辟一块更大的空间

    voidresize(size_t size);

 

    //初始化数组中每个元素

    voidinitElements();

 

private:

    T       *m_elements;//数组裸指针

    size_t  m_size;//数组尺寸

};

 

//包含模板实现部分

//如果"MyArray.inl"是头文件就直接包含就行

//如果"MyArray.inl"是源文件,则必须将其从项目中移除

#include "MyArray.inl"

 

 

 

//MyArray.inl

template <typenameT>

MyArray<T>::MyArray(size_t size/* = 0*/)

{

    if(size<= 0)

    {

        m_size= 0;

        m_elements= nullptr;

        return;

    }

 

    m_size = size;

    m_elements= new T[m_size];

    initElements();

}

 

template <typenameT>

MyArray<T>::~MyArray()

{

    if(nullptr!= m_elements)

    {

        delete[]m_elements;

        m_elements= nullptr;

        m_size= 0;

    }

}

 

template <typenameT>

T& MyArray<T>::operator [] (size_tindex)

{

    size_t size = 0;

    if(index>= m_size)

    {

        if(2*m_size > index)

        {

            size= 2 * m_size;

        }

        else

        {

            size= index + 1;

        }

       

        resize(size);

    }

 

    returnm_elements[index];

}

 

template <typenameT>

const T&MyArray<T>::operator[] (size_t index)const

{

    if(index>= m_size)

    {

        throwstd::out_of_range("数组访问越界!");

    }

 

    returnm_elements[index];

}

 

template <typenameT>

void MyArray<T>::resize(size_tsize)

{

    //将原数组的内存和尺寸保存起来

    T *oldElements = m_elements;

    size_t oldSize = m_size;

 

    //分配新内存

    m_size = size;

    m_elements= new T[m_size];

 

    //初始化新分配的内存空间

    initElements();

 

    //拷贝

    for(size_t i = 0; i < oldSize; ++i)

    {

        m_elements[i]= oldElements[i];

    }

 

    //释放原数组内存空间

    delete[]oldElements;

    oldElements= nullptr;

}

 

template <typenameT>

void MyArray<T>::initElements()

{

    for(size_t i = 0; i < m_size; ++i)

    {

        m_elements[i]= T();

    }

}

 

template <typenameT>

rsize_t MyArray<T>::getSize() const

{

    returnm_size;

}

 

template <typenameT>

T* MyArray<T>::operator + (rsize_tindex)

{

    if(index>= m_size)

    {

        throwstd::out_of_range("数组访问越界!");

    }

 

    return(m_elements + index);

}

 

template <typenameT>

const T*MyArray<T>::operator+ (rsize_t index)const

{

    if(index>= m_size)

    {

        throwstd::out_of_range("数组访问越界!");

    }

 

    return(m_elements + index);

}

 

template <typenameT>

void MyArray<T>::show() const

{

    cout<< "{";

    for(size_t i = 0; i < m_size; ++i)

    {

        cout<< m_elements[i] << ", ";

    }

    cout<< "}" << endl;

}

 

template <typenameT>

T MyArray<T>::operator * ()

{

    return*(operator + (0));

}

 

template <typenameT>

const TMyArray<T>::operator* () const

{

    return*(operator + (0));

}

 

 

//main.cpp

#include "MyArray.h"

 

int main(int argc,char **argv)

{

    cout<< "into main"<< endl;

 

    try

    {

        //使用自定义数组类定义一个有10int型元素的数组

        MyArray<int>nArray(10);

 

        //通过下标访问运算符给数组每个元素进行初始化

        for(size_t i = 0; i < nArray.getSize(); ++i)

        {

            nArray[i]= i;

        }

 

        //输出数组中每个元素

        cout<< "nArray = ";

        nArray.show();

 

        //通过operator + 返回数组中元素的地址

        //再通过返回的地址访问元素存储空间

        cout<< *(nArray + 3) << endl;

        *(nArray+ 2) = 7;

 

        //输出数组中每个元素

        cout<< "nArray = ";

        nArray.show();

 

        //越界访问数组元素,将抛出数组访问越界异常

        //cout<< *(nArray + 10) << endl;

 

        //当数组空间不够时,重新开辟一块新的空间

        cout<< "size = "<< nArray.getSize() << endl;

        nArray[10]= 80;

        cout<< "size = "<< nArray.getSize() << endl;

 

        //由于数组名是常量,不可以修改,否则编译器会报错。

        //cout<< (++nArray) << endl;

 

        //数组名是数组第一个元素的地址

        cout<< "*nArray = "<< *nArray << endl;

 

        nArray.show();

    }

    catch(conststd::out_of_range &e)

    {

        cout<< "in main caught a exception: "<< e.what() << endl;

    }

 

    cout<< "out of main"<< endl;

 

    return0;

}

 

程序运行结果:


         怎么样,封装一个简单的动态数组也就这么easy!如果想加深对运算符重载的理解,就得多编写类型的程序,尝试着去封装一些类模板,练着练着你的境界就不一样啦。通过博主封装的MyArray类模板实例的学习,相信大家已经对下标访问运算符重载掌握的差不多了。如果你还没有搞清楚这个实例,那么就得加把劲了。你可以编写一些简单的实例,去尝试着运用它们,就算错了也是一种收获。

       C++运算符重载中的算术运算符重载就讲到这里,相信大家对它的概念和用法都已经熟悉了吧。如果想了解更多关于C++运算符重载的知识,请关注博主的《C++运算符重载》系列博文,在那里我们将会通过程序实例去探讨C++运算符重载的魅力,相信你在那里会有不一样的收获。当然,如果你对C++很感兴趣的话,那么请关注博主的《漫谈继承技术》和《灵活而奇特的C++语言特性》系列博文,在那里你也许会发现C++更大的魅力,让你对这门博大精深的语言更加爱不释手。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值