您的位置:首页 > 其它

两层指针共用一个智能指针控制基本对象的操作--成员访问操作符

2012-04-26 23:09 573 查看
智能指针,让ScreenPtr指向ScrPtr,来控制基础对象

ScreenPtr(Screen *p): ptr(new ScrPtr(p)) {}
解引用和箭头操作

	Screen
	operator*(){return *ptr->sp;}
	Screen*
	operator->(){return ptr->sp;}


两个小缺陷,第一个是未定义const版本,第二个是返回的非引用,返回的副本,这样每次多一个复制操作

关于const的必要性也再次加深印象,第一个缺陷:

ScreenPtr ps(new Screen(4, 4));
	const ScreenPtr ps2(new Screen(3, 3));//很容易就会出现const类型,必须兼容,非const无所谓了
	
	std::cout << (*ps).get() << ": " << ps->get() << std::endl;//测试成功
	std::cout << (*ps2).get() << ": " << ps2->get() <<  std::endl;//失败,所以要求必须有const版本(多验证几次就有记性了)
}
验证第二个小缺陷,因为返回非引用,而是副本,导致修改无效。

std::cout << (*ps).getTest() << std::endl;
	(*ps).setTest(3);
	std::cout << (*ps).getTest() << std::endl;


正确的声明:const重载,operator*返回引用

public:
	Screen&
	operator*(){return *ptr->sp;}
	Screen*
	operator->(){return ptr->sp;}
	const Screen&
	operator*() const{return *ptr->sp;}
	const Screen*
	operator->() const{return ptr->sp;}
返回引用以方便修改(减少复制的资源消耗),返回const以避免修改(也为了能让const对象传入吧)。。。。

都是成员函数,operator*没显式形参(有的话该和乘法混了吧?

,operator->不接收显式形参(左操作数是对象,右操作数是成员名)

箭头操作符很特殊

对于 point->action()

//如果point是指针,获取指针指向的类对象的action成员(也就是类似以前常用的(&pair1)->first,this->price;)

if(point是个对象 && 自定义箭头操作符){

point.operator->()->action;//等价于point调用->操作后的action成员

if(point.operator->()返回的结果不是指向含有action成员的对象)

废了;

else

继续执行->来读取action成员

}

class Point{
public:
	int action(){return 1;}
	Point*//返回的是引用
	operator->(){
		std::cout << "call operator-> " << std::endl;
		return ptr;}
	Point* ptr;
private:
	
};

int main(){
	Point point;
	Point* ptr = &point;
	std::cout << point.action() << std::endl;
	std::cout << ptr->action() << std::endl;//ptr是指针的情况下
	std::cout << (point.operator->()->action()) << std::endl;//point.operator->()的作用是获得一个指针(等价&point),然后指针和->成员对应
    std::cout << (&point)->action() << std::endl;//这也约束了重载箭头操作符的返回类型必须是Point*类型
 std::cout << (point->action()) << std::endl;
}


pe14_21.cpp

有几要点:四个类通过指针串起来,要注意下层和较高层都要给最高层提供friend功能,因为要访问到他的成员的

还有就是,如果箭头都定义好了,一个箭头就相当于一串箭头

多层次析构的判断条件问题

两层指针共用一层只能指针的问题

递归之后的析构问题,计数,层级。

//定义一个类,保存一个指向Screen_Ptr的指针,重载箭头操作符
//定义了比较严密的顺序,保证从上到下的计数和析构,不过差一个以ScreenPtr为对象的ScreenPtrPtr初始化,这样就能让两层对象共用一个计数器
//还有一个小bug,递归过程中使用--use == 0 判断,导致实际把use减到比0还小,因为无符号类型,直接溢出,判断失常,用了一个短路或来判断
//不要留尾巴,测试用的附加操作一定要即使注释掉,like: delete ptrptr; delete ptr;这种双重析构

#include"head.h"
class Screen{
public:    
    ~Screen(){std::cout << "calling ~Screen().... " << std::endl;}
    typedef std::string::size_type index;//利用typedef
    char get() const{
        //return contents[cursor];
        return 'T';//test
    }//重载
    void setTest(index i){cursor = i;}
    index getTest(){return cursor;}
    inline char get(index ht, index wd) const;//显式定义inline
    index get_cursor() const;//后者便于阅读,在类的定义里的声明比较清晰
    void set_height(index i){height = i;}
    index get_height() const{return height;}
public:
    Screen(index ht, index wd): height(ht), width(wd) {}
private:
    std::string contents;
    index cursor;//光标
    index height, width;//同时声明多个
};

class ScrPtr{
public://为了测试建立一个ScrPtr对象
    friend class ScreenPtr;
    friend class ScreenPtrPtr;
    Screen *sp;
    size_t use;
    ScrPtr(Screen *p): sp(p), use(1) {}

    ~ScrPtr() {
        if(use == 0 || --use == 0){
            std::cout << "calling ~ScrPtr().... " << std::endl;
            delete sp;
        }
    }
};

class ScreenPtr{
    friend class ScreenPtrPtr;
public:
    ScreenPtr(Screen *p): ptr(new ScrPtr(p)) {}
    ScreenPtr(const ScreenPtr& orig): ptr(orig.ptr) {++ptr->use;}
    ~ScreenPtr() {
        
        if(ptr->use == 0 || --ptr->use == 0){
            std::cout << "calling ~ScreenPtr().... " << std::endl;
            delete ptr;
        }
        std::cout << "ptr->use : " << ptr->use << std::endl;
    }
public:
    void display(){}
    
public:
    Screen&
    operator*(){return *ptr->sp;}
    Screen*
    operator->(){return ptr->sp;}
    const Screen&
    operator*() const{return *ptr->sp;}
    const Screen*
    operator->() const{return ptr->sp;}
    
    ScreenPtr&
    operator=(const ScreenPtr& rhs);
private:
    ScrPtr *ptr;
};

class ScreenPtrPtr{//我就不去改ScreenPtr了,不加计数器了
public:
    ScreenPtrPtr(Screen *p): ptrptr(new ScreenPtr(p)) {}
    ScreenPtrPtr(const ScreenPtrPtr& orig): ptrptr(orig.ptrptr) {++ptrptr->ptr->use;}
    ScreenPtrPtr(const ScreenPtr& orig): ptrptr(&orig) {++ptrptr->ptr->use;}
    
    ~ScreenPtrPtr() {
        
        if(ptrptr->ptr->use == 0 || --ptrptr->ptr->use == 0){
            std::cout << "calling ~ScreenPtrPtr().... " << std::endl;
            delete ptrptr;
        }
    }
    
public:
    void display(){}
public:
    ScrPtr*
    operator->(){return ptrptr->ptr;}
    const ScrPtr*
    operator->() const{return ptrptr->ptr;}    
    ScreenPtrPtr&
    operator=(const ScreenPtrPtr& rhs){
        rhs.ptrptr->ptr->use++;
        ptrptr->ptr->sp = rhs.ptrptr->ptr->sp;
        return *this;
    }
private:
    const ScreenPtr *ptrptr;//为了便于最后一种构造函数的定义
};

char Screen::get(index r, index c) const{
    index row = r * width;
    return contents[row + c];    
}
inline Screen::index Screen::get_cursor() const{
    return cursor;
}
ScreenPtr&
ScreenPtr::operator=(const ScreenPtr& rhs){
    rhs.ptr->use++;
    ptr->sp = rhs.ptr->sp;
    return *this;
}
int main(){
    
    ScreenPtrPtr p(new Screen(4, 4));//一个析构    
    std::cout << "===============" << std::endl;
    
    ScreenPtrPtr p2(p);//p2和p1会最后一个灭亡的会调用一个ScreenPtr的析构函数(其实没什么用)
    ScreenPtr p3(new Screen(3, 3));//此句顺序执行3个析构函数
    ScrPtr p4(new Screen(2, 2));//顺序析构两个
    /*std::cout << p->sp->get_height() << std::endl;//测试箭头等价关系(我改了,可以多加基层箭头)
    std::cout << p.operator->()->sp->get_height() << std::endl;//这句怎么不认的?傻了半天,多了半个括号
    std::cout << (p3.operator->()->get_height()) << std::endl;
    std::cout << (p4.sp->get_height()) << std::endl;
    
    
    ScreenPtrPtr p5(new Screen(1, 1));
    ScreenPtrPtr p6(new Screen(1, 1));
    p5 = p;
    p6 = p5;
    
    
    //测试跨层共同计数,缺点,高层必须以低层对象来初始化,顺序问题,无法调用ScreenPtrPtr的析构函数
    ScreenPtr p(new Screen(4 ,4));
    ScreenPtr p2(p);
    ScreenPtrPtr pp(p);
    ScreenPtrPtr pp2(new Screen(3 , 3));
    //麻烦,意义不大,层级不同,建立顺序不同,删除顺序有所不同,最后也无法利用公共计数递归析构,以后有空再回看一眼把
    */
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐