前面的操作符都比较一般,但是这里的调用就有点小不同了,如下设计的类(与智能指针类似)
class ScrPtr
{
public:
friend class ScreenPtr;
friend class ScrPtrTest; //这个先不用管,后面我会用到
ScrPtr(screen* p):sp(p),count(1) { };
~ScrPtr() { /*delete sp;*/ };
private:
size_t count;
screen *sp;
};
这里又使用了智能指针,指针指向的就是screen类对象,其他与智能指针一致,调用指针的类,如下
class ScreenPtr
{
public:
friend class ScrPtrTest; //这个也不用管
ScreenPtr(void);
~ScreenPtr(void);
ScreenPtr(screen *p);
ScreenPtr(const ScreenPtr&);
ScreenPtr& operator=(const ScreenPtr &);
screen* operator->() { return ptr->sp; }; //箭头操作符
screen& operator*() { return *ptr->sp; }; //解引用操作符
const screen* operator->() const { return ptr->sp; }; //const版本的箭头操作符
const screen& operator*() const { return *ptr->sp; }; //const版本的解引用操作符
private:
ScrPtr* ptr;
};
这里我定义了箭头操作符->和解引用操作符*,这里也定义了两个版本,当然定义也没什么,无非返回值,形参,指针如何传递值,关键如何使用呢?通常应该这样:obj.operator().xx肯定是正确的,这里我们定义了->,当然最好使用箭头了obj->,关键这个指向谁呢?或者说返回什么呢?其实就是定义的函数的screen*(这里不考虑const的调用),所以就可以直接调用screen内的成员了,因为obj->就是screen*类型的对象指针,所以就能调用可见的成员了。如下测试用例:
string str = "windows_title";
screen myscreen(str, 0, 5); //栈上分配的空间
myscreen.display(cout);
cout<<"-----#####-----" <<endl;
ScreenPtr p(&myscreen);
p->display(cout);
p.operator->()->display(cout); //两种调用方式是一样的
总结几个注意的地方:
(1)箭头操作必须定义为类成员函数,解引用操作符不要求定义为成员
(2)不管如何调用。箭头操作符不接受显式形参
(3)重载箭头必须返回指向类类型的指针,或者返回定义了自己的箭头操作符的类类型对象
(4)如果返回类型是类类型的其他对象,则将递归应用该操作符
下面就看第四个设计下的一个类:
class ScrPtrTest
{
public:
ScrPtrTest(screen *p): ptr(new ScreenPtr(p)) { };
~ScrPtrTest() { if (--ptr->ptr->count ==0) delete ptr; }
ScrPtrTest(const ScrPtrTest&);
ScrPtrTest& operator=(const ScrPtrTest &);
screen* operator->() { return ptr->ptr->sp; }; //箭头操作符
const screen* operator->() const { return ptr->ptr->sp; }; //const版本的箭头操作符
private:
ScreenPtr* ptr;
};
注意:这个类有些不完善,只是说明问题,但是根据C++Primer意思就是逐层递归,这样一类设计的类就如上,调用如下
ScrPtrTest test(&myscreen);
test->display(cout);
会跟上面的ScreenPtr对象的调用结果是一致的,但是这里破坏类的封装较大。