我是靠谱客的博主 震动羊,这篇文章主要介绍两层指针共用一个智能指针控制基本对象的操作--成员访问操作符,现在分享给大家,希望可以做个参考。





智能指针,让ScreenPtr指向ScrPtr,来控制基础对象

复制代码
1
ScreenPtr(Screen *p): ptr(new ScrPtr(p)) {}
解引用和箭头操作
复制代码
1
2
3
4
Screen operator*(){return *ptr->sp;} Screen* operator->(){return ptr->sp;}

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

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

复制代码
1
2
3
4
5
6
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版本(多验证几次就有记性了) }
验证第二个小缺陷,因为返回非引用,而是副本,导致修改无效。
复制代码
1
2
3
4
std::cout << (*ps).getTest() << std::endl; (*ps).setTest(3); std::cout << (*ps).getTest() << std::endl;


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

复制代码
1
2
3
4
5
6
7
8
9
10
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成员

}



复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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功能,因为要访问到他的成员的

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

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

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

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

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//定义一个类,保存一个指向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));     //麻烦,意义不大,层级不同,建立顺序不同,删除顺序有所不同,最后也无法利用公共计数递归析构,以后有空再回看一眼把     */ }


最后

以上就是震动羊最近收集整理的关于两层指针共用一个智能指针控制基本对象的操作--成员访问操作符的全部内容,更多相关两层指针共用一个智能指针控制基本对象内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(70)

评论列表共有 0 条评论

立即
投稿
返回
顶部