概述
智能指针,让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));
//麻烦,意义不大,层级不同,建立顺序不同,删除顺序有所不同,最后也无法利用公共计数递归析构,以后有空再回看一眼把
*/
}
最后
以上就是震动羊为你收集整理的两层指针共用一个智能指针控制基本对象的操作--成员访问操作符的全部内容,希望文章能够帮你解决两层指针共用一个智能指针控制基本对象的操作--成员访问操作符所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复