两层指针共用一个智能指针控制基本对象的操作--成员访问操作符
2012-04-26 23:09
573 查看
智能指针,让ScreenPtr指向ScrPtr,来控制基础对象
两个小缺陷,第一个是未定义const版本,第二个是返回的非引用,返回的副本,这样每次多一个复制操作
关于const的必要性也再次加深印象,第一个缺陷:
正确的声明:const重载,operator*返回引用
都是成员函数,operator*没显式形参(有的话该和乘法混了吧?)
,operator->不接收显式形参(左操作数是对象,右操作数是成员名)
箭头操作符很特殊
对于 point->action()
//如果point是指针,获取指针指向的类对象的action成员(也就是类似以前常用的(&pair1)->first,this->price;)
if(point是个对象 && 自定义箭头操作符){
point.operator->()->action;//等价于point调用->操作后的action成员
if(point.operator->()返回的结果不是指向含有action成员的对象)
废了;
else
继续执行->来读取action成员
}
pe14_21.cpp
有几要点:四个类通过指针串起来,要注意下层和较高层都要给最高层提供friend功能,因为要访问到他的成员的
还有就是,如果箭头都定义好了,一个箭头就相当于一串箭头
多层次析构的判断条件问题
两层指针共用一层只能指针的问题
递归之后的析构问题,计数,层级。
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)); //麻烦,意义不大,层级不同,建立顺序不同,删除顺序有所不同,最后也无法利用公共计数递归析构,以后有空再回看一眼把 */ }
相关文章推荐
- 通过指针运算符访问对象成员和构造函数的特点
- this指针访问对象的数据成员
- 鸡啄米:C++编程入门系列之十三(类与对象:类的声明、成员的访问控制和对象)
- 同一个类不同对象,可以互相访问对方的私有成员而不通过get()或set()
- 对用父类指针(或引用)指向父类对象和子类对象时,从而用父类指针或者引用访问成员时的深刻理解;
- C++初始化列表问题,类中有一个对象类型的数组成员变量,在初始化列表中初始化时报错“[]”操作符语法错误
- 类和对象的存储、访问控制及类成员类型变化
- Java线程:线程的同步与锁 一、同步问题提出 线程的同步是为了防止多个线程访问一个数据对象时,对数据造成的破坏。 例如:两个线程ThreadA、ThreadB都操作同一个对象Foo对
- 理解类级别的访问控制权限——类的成员函数可以访问该类所有对象的私有成员
- VC++6.0中定义一个类的对象后,用“.”访问其成员函数和成员变量时,其成员函数和成员变量没有自动弹出
- 【转载】c++之类的基本操作(c++ primer 的读书笔记 ,类对象, 类用户, 类成员的含义)
- 类中的this指针 一个类的指针指向NULL去访问该类的成员函数
- 用基类指针创建的派生类对象,无法访问派生类对象的数据和成员
- 通过指针对结构体成员对象的访问输出C/C++
- C++编程入门系列之十三(类与对象:类的声明、成员的访问控制和对象)
- 关于Objective-C 对象release操作野指针的一个小问题探讨
- 为什么一个对象调用的类方法可以访问该类其他对象的私有成员
- KVC的使用(对一个对象的成员变量进行操作(赋值/取值))
- 神奇的虚函数:用基类指针访问对象的protected成员函数
- C++的引用计数j控制智能指针——>Java的引用计数管理共享对象