关于上一讲我们留下的问题,我们暂且搁在一旁,留给大家去思考我觉得比我现在说出来要好得多,因为现在有更重要的东西要说,从大局观上来说,我们应该要来说说一些关于我们的My_Point,为了让我们下面的代码能够得以运行:
—————————–
1)My_Array<int>*a = new My_Array<int>(10);
2)My_Point<int>p(*a);
3)My_Point<int>p1(*a,5);
——————————
我们现在来分析一下这个类的构造,首先我们要明白一件事,那就是*a并不是int,而是My_Array的对象,不过是经过int具体化后的,而且My_Point居然是指针(我们想要达到内建指针的效果的指针),所以我们的My_Point应该封装一个指向My_Array<T>的指针,并不是指向一个T的指针,说到这里,如果大家对STL熟悉的话应该看出了一些东西出来,当然,我们接下来会说。
我们来看第二句,要让第二句安全的运行起来,我们就应该有一个像下面这样一个构造函数:
—————————–
My_Point(const My_Array<T>&
);
——————————
不过,我们这里还有一个问题,我们并没有表示const My_Array的类,所以我们现在的构造函数还得修改一下,就是去掉const,然后我们再来看看第三句,在第三句里,虽然说我们没有给出原型,但是想必大家一定知道,里面的两个参数应该是My_Array的对象和一个下标,所以我们还得有另一个构造函数,如下:
——————————-
My_Point(My_Array<T>&
t,int n);
——————————-
从这两句话中,我们几乎可以得出,My_Point里面的两个成员数据分别为:
————————–
My_Array<T>* m_Ptr;
unisgned
int m_Size;
————————–
现在我们几乎可以得出一个可以用的My_Point了,他最初的样子就像下面这样:
—————————–
template<typename T>
class My_Point{
public:
My_Point():
m_Ptr(0),m_Size(0)
{ }
My_Point(My_Array<T>&
t):
m_Ptr(&
t)
{
m_Size = t.Size();
}
My_Point(My_Array<T>&
t,int n):
m_Ptr(&
t),m_Size(n)
{ }
T&
operator*() const{
return (*m_Ptr)[m_Size-1];
}
T operator[](int n){
return (*m_Ptr)[n];
}
My_Point(const My_Point&
);
My_Point&
operator=(const My_Point&
);
private:
My_Array<T>* m_Ptr;
unsigned
int m_Size;
};
—————————————-
现在,我们下面的代码就能够运行了:
——————————–
My_Array<int>*a = new My_Array<int>(10);
for(int i=0;
i<10;
i++)
a->insert(i,i);
My_Point<int>p(*a);
*p = 42;
cout<<endl;
cout<<*p<<"
"
<<(*a)[9]<<endl;
My_Point<int>p1(*a,5);
*p1 = 42;
cout<<*p1<<"
"
<<(*a)[4]<<endl;
——————————-
上面的代码有一个问题,大家想想,如果我们的解引用返回的是一个T&
,那么我们可以对*p赋值,但是这样一来,同时也就会运行我们这样的代码通过编译:
——————-
T* t = &
*p;
——————-
这种写法极其怪异,所以,我们当然不希望写出这样的代码出来,如果有人非要这么写,我们给他一个编译错误,所以,我们不能让他返回引用,让他返回T,只是这样一来,我们好像无法更新元素了,不过我们可以使用另一种方式来更新元素,比如说我们添加一个名叫Set的方法:
——————————-
void Set(const T t){
if(m_Ptr)
(*m_Ptr)[m_Size] = t;
}
为了方便,我们再添加一个同名方法:
void Set(int n,const T t){
if(n<0 || n>m_Size)
throw "
over range!!!"
;
(*m_Ptr)[n] = t;
}
———————————-
当然,如果我们使用Set去更新元素的话,那么我们会重新带来一个问题,这个问题留待下一讲吧,现在我们来整理一下我们的My_Point,然后看看他还缺少些什么。
————————————–
template<typename T>
class My_Point{
public:
My_Point():
m_Ptr(0),m_Size(0)
{ }
My_Point(My_Array<T>&
t):
m_Ptr(&
t)
{
m_Size = t.Size();
}
My_Point(My_Array<T>&
t,int n):
m_Ptr(&
t),m_Size(n-1)
{ }
T&
operator*() const{
return (*m_Ptr)[m_Size];
}
T operator[](int n){
return (*m_Ptr)[n];
}
void Set(const T t){
(*m_Ptr)[m_Size] = t;
}
void Set(int n,const T t){
if(n<0 || n>m_Size)
throw "
over range!!!"
;
(*m_Ptr)[n] = t;
}
My_Point(const My_Point&
);
My_Point&
operator=(const My_Point&
);
private:
My_Array<T>* m_Ptr;
unsigned
int m_Size;
};
———————————————
至此,我们要实现的功能完成得差不多了,但是还是有很多问题,就比如我们上面的class里面还有个缺陷,留给大家思考,而且他依然不能让下面的代码顺利执行:
——————————–
My_Array<SpreadSheetCell>* m_Array = new My_Array<SpreadSheetCell>(10);
My_Point<SpreadSheetCell>m_ptr(m_Array,3);
delete m_Array;
m_ptr.Set("
Hello"
);
———————————-
现在看来我们要面对的问题是越来愈多了,大家要思考的也越来越多,哎,想要构架出一个完美的框架还真不是一件容易的事啊。这些问题还是留给大家去思考,我们下周再见。
=================
回复D直接查看目录
原文始发于微信公众号(
C/C++的编程教室
):第五十八讲 迭代器(3)
|