第五十九讲 迭代器(4)

回顾上周我们留下的问题:
———————————-
My_Array<SpreadSheetCell>* m_Array = new My_Array<SpreadSheetCell>(10);


My_Point<SpreadSheetCell>m_ptr(*m_Array,3);


delete m_Array;


*m_ptr = "

Hello"

;


———————————–

还是这段程序,要让这段程序运行起来,我们由目前的My_Array和My_Point还是无法做到。不过,还记得我们前面说过的关于引用计数这技术吗?当时我们用他实现一个智能指针,让他管理内存,回收内存,虽然我们这里没有实现智能指针,但是我们一样实现这类型的东西,而且配合容器使用功能会相当的强大,所以今天我们的任务就是让上面这段程序运行起来。

为了让上面这段程序运行起来,我们引入引用数据,但是我们是要把这技术用在My_Array里呢还是My_Point里呢?嗯,我想大家都应该清楚,要实现数据抽象,所以我们应该添加一个数据层,这给类就是用来储存数据,而不足外人道人也,让My_Array和My_Point成为他的友元类。

当我们构造一个My_Array对象的时候其实构造的是数据类的对象,而当我们销毁My_Array对象的时候再根据数据层的计数器来判断是否真要销毁底层对象。

现在又面临着一个问题,计数器虽然在底层,那么我们怎么实现他的增减呢?是在My_Array中呢还是在My_Point中呢?首先我们要明白一件事,那就是My_Array负责的其实不过就是构建对象而已,所以,他里面如果我们要实现计数器,事情就变得更加的麻烦了,所以,管理计数,我们就交给My_Point,谁叫他这么喜欢粘人家呢?

还有一点,对于My_Array的复制构造,复制操作我们可能会遇到一些问题,如果说我们直接调用底层的复制构造和复制操作的话会引来一个我们现在一直想要回避的问题,所以说我们应该回避底层的复制和赋值,现在看来我们几乎可以得出底层数据类型的大概样貌了。
———————————
template<typename T>

class My_Array_Data{

friend class My_Array<T>;


friend class My_Point<T>;

My_Array_Data(unsigned n=0):

m_Size(n),Data(new T[m_Size]),m_Count(1)

{

}


~My_Array_Data(){

delete[] Data;


}

const T&

operator[](int n) const{

if(n>m_Size)

throw "

over range!!!"

;


return Data[n];


}

T&

operator[](unsigned n){

if(n>m_Size)

throw "

Over range!!!"

;


return Data[n];


}


friend ostream&

operator<<(ostream&

out,const My_Array_Data<T>&

t){

return out<<*t.Data;


}

//下面这两个函数只声明不定义,防止复制和赋值

My_Array_Data(const My_Array_Data&

);


My_Array_Data&

operator=(const My_Array_Data&

);

unsigned m_Size;


T* Data;


int m_Count;



};


——————————————

说到这里顺便给大家提个醒,友元类不是这样friend class My_Array<T>就好的,要想顺利通过编译,我们还要在我们的底层类的前面使用前向声明的方式将要作为友元的两个类声明出来:
——————————–
template<typename T>

class My_Array;


template<typename T>

class My_Point;


——————————-

前向声明的活儿好像我们以前说过了,不过这里顺带提一下,就是说,当我们还没明显的定义好一个类时,但是我们目前的类有需要用到的时候,我们可以前向声明该类,以后再定义,而现在我们需要用这两个类来做这个底层数据类的友元,同样也需要前向声明这两个类。

有了这个类之后,我们可以来可以来处理My_Array了,从我们的分析中,我们应该明白一件事,My_Array其实是封装了底层数据的指针,所以,而且让他和My_Point很好的关联,而且让My_Point很好的管理计数器,我们也让My_Point成为My_Array的友元,从前面两讲的内容,我们可以很快的写出My_Point和My_Array出来:
——————————————
template<typename T>

class My_Array{

public:

My_Array(unsigned size=0):

m_Data(new My_Array_Data<T>(size))

{

}

~My_Array(){

if(–m_Data->m_Count==0)

delete m_Data;


}

T&

operator[](unsigned n){

return (*m_Data)[n];


}

const T&

operator[](unsigned n) const{

return (*m_Data)[n];


}

const T&

operator*(unsigned n)const{

if(n>mm_Size)

throw "

Over range!!!"

;


return (*m_Data)[n];


}

T&

operator*(unsigned n){

if(n>m_Size)

throw "

voer range!!!"

;


return (*m_Data)[n];


}

friend ostream&

operator<<(ostream&

out,const My_Array<T>&

t)

{

return out<<*t.m_Data;


}

friend class My_Point<T>;


private:

My_Array_Data<T>* m_Data;


My_Array(const My_Array&

);


My_Array&

operator=(const My_Array&

);



};


—————————————————

真正核心的部分是My_Point,因为计数管理都是在这里。
———————————————
template<typename T>

class My_Point{

public:

My_Point():

m_Ptr(0),m_Sub(0)

{

}

My_Point(My_Array<T>&

t):

m_Ptr(t.m_Data),m_Sub(0)

{

++m_Ptr->m_Count;


}

My_Point(My_Array<T>&

t,int n):

m_Ptr(t.m_Data),m_Sub(n)

{

++m_Ptr->m_Count;


}

T&

operator*() const{

return (*m_Ptr)[m_Sub];


}

T&

operator[](int n){

return (*m_Ptr)[n];


}

My_Point(const My_Point&

);


My_Point&

operator=(const My_Point&

);


private:

My_Array_Data<T>* m_Ptr;


unsigned
int m_Sub;



};


———————————————-

至此,我们的程序可以运行了。

我们今天只是让这段程序运行起来,还有很多功能需要添加呢,留待大家去思考吧,对了,有朋友问,怎么定义一个学生成绩的类,同样这个问题还是留给大家去思考。
==========================
回复D直接查看目录


原文始发于微信公众号(

C/C++的编程教室

):第五十九讲 迭代器(4)

|

发表评论