当前位置: 首页 > wzjs >正文

免费域名网站黄华辰合肥企业展厅设计公司

免费域名网站黄,华辰合肥企业展厅设计公司,南平抖音搜索排名seo软件,要怎么做网站目录 成员访问运算符 两层结构下的使用 三层结构下的使用(难点) 内存分析 成员访问运算符 成员访问运算符包括箭头访问运算符 -> 和解引用运算符 * ,它们是指针操作最常用的两个运算符。我们先来看箭头运算符 -> 箭头运算符只能以…

目录

成员访问运算符

两层结构下的使用

三层结构下的使用(难点)

内存分析


成员访问运算符

成员访问运算符包括箭头访问运算符 -> 和解引用运算符 * ,它们是指针操作最常用的两个运算符。我们先来看箭头运算符 ->

箭头运算符只能以成员函数的形式重载,其返回值必须是一个指针或者重载了箭头运算符的对象。来看下例子:

两层结构下的使用

例子:建立一个双层的结构,MiddleLayer含有一个Data*型的数据成员

image-20231127173105700

image-20231127173356110

栈帧结束,栈帧结束,ml会调用析构函数,会delete _pdata 空间所以 ml 管理的对象至少应该在堆上的空间

Data*原生指针的用法如下,需要关注堆空间资源的回收

Data * p = new Data();
p->getData();
(*p).getData();
delete p;
p = nullptr;

如果用这种方式创建MiddleLayer对象,我们发现不需要手动delet pdata,并没有发生内存泄露,反而手动delet pdata后会有double free的问题

 

因为MiddleLayer对象实际上对堆上Data对象形成了接管。当函数栈帧结束会自动调用析构函数将堆上的空间回收,所以如果再次手动调用delete pdata 会出现double free的问题。

当然,也可以让Middlelayer对象自己管理一个Data对象,这样就不会出现那种情况了。

image-20240314112042932

image-20240314112053390

需求:希望实现一个这样的效果,创建MiddleLayer对象ml,让ml对象可以使用箭头运算符去调用Data类的成员函数getData

MiddleLayer ml(new Data);
cout << ml->getData() << endl;

箭头运算符无法应对MiddleLayer对象,那么可以定义箭头运算符重载函数。

  • 首先不用考虑重载形式,箭头运算符必须以成员函数形式重载;

  • 然后考虑返回类型,返回值需要使用箭头运算符调用getData函数,而原生的用法只有Data* 才能这么用,所以返回值应该是一个Data* ,此时应该直接返回 _pdata;

  • 同时考虑到一个问题:MiddleLayer的数据成员是一个Data*,创建MiddleLayer对象时初始化这个指针,让其指向了堆上的Data对象,那么还应该补充析构函数使MiddleLayer对象销毁时能够回收这片堆上的资源。

Data* operator->(){return _pdata;
}

思考,解引用运算符应该如何重载能够实现同样的效果呢?直接使用MiddleLayer对象模仿Data*指针去访问getData函数

image-20240314113617206

image-20240314113636052

image-20240314113714656

 

当我们完成了以上的需求后,还有一件“神奇”的事情,使用的语句中有new没有delete,但是检查发现并没有内存泄漏

原因:ml本身是一个局部对象,因为重载了箭头运算符和解引用运算符,所以看起来像个指针,也可以像指针一样进行使用,但是这个对象在栈帧结束时会自动销毁,自动调用析构函数回收了它的数据成员所申请的堆空间

实际上,这就是智能指针的雏形:其思想就是通过对象的生命周期来管理资源。

下面为测试代码,可以自行进行测试

#include<iostream>
using namespace std;
class Data {
public ://构造函数Data(){cout << "Data()" << endl;}Data(int x):_data(x){cout << "Data(int)" << endl;}int get()const { return _data; }~Data() { cout << "~Data()" << endl; }
private:int _data = 10;
};class middlelayer {
public:middlelayer(Data* p):_pdata(p){cout << "middlelayer(Data*)" << endl;}~middlelayer() {if (_pdata) {delete _pdata;_pdata = nullptr;}}Data * operator->(){return _pdata;}//要返回一个data对象,才可以用点来Data& operator* (){return *_pdata;}
private:Data* _pdata;
};void test()
{//下面两行代码会出错,因为栈帧结束,ml会调用析构函数,所以ml管理的对象至少应该在堆上的空间/*Data d1;middlelayer ml( &d1);*///不建议这样使用,//因为如果手动的通过p1指针来回收堆上的Data对象空间//会出现double free的问题Data* p1 = new Data();cout << p1->get() << endl;cout << (*p1).get() << endl;middlelayer ml(p1);//delete p1;
}
void test1()
{Data* p1 = new Data();cout << p1->get() << endl;cout << (*p1).get() << endl;delete p1;//智能指针的雏形//利用局部对象的生命周期管理堆上的资源//ml是middlelayer类对象,不是指针//但是可以像原生的data* 指针一样使用箭头运算符和解引用运算符//访问data的成员//并且,不需要像原生的指针一样去手动调用回收堆上的data空阿金middlelayer ml(new Data());//为什么可以进行重载呢,因为middlelayer底层的原型就是data类型cout << ml->get() << endl;//如下是middlelayer使用箭头运算符访问data类成员函数的本质形式//ml对象调用operator->函数,返回值是一个Data*//编译器自动加上了一个->原生的箭头运算符cout << ml.operator->()->get() << endl;cout << (*ml).get() << endl;cout << ml.operator*().get() << endl;//本质形式
}
int main()
{test1();return 0;
}
三层结构下的使用(难点)
  • 拓展思考:那么如果结构再加一层,引入一个ThirdLayer类

创建ThirdLayer对象时注意避免这样的错误

注意:应该让ThirdLayer底层的指针管理一个堆上的MiddleLayer对象

希望实现如下使用方式,思考一下应该如何对ThirdLayer进行对应的运算符重载

ThirdLayer tl(new MiddleLayer(new Data));
cout << tl->getData() << endl;
cout << (*(*tl)).getData() << endl;

在ThirdLayer类中定义这两个成员函数

—— 在使用时就可以这样用

箭头运算符的使用:

解引用运算符的使用:

  • 拓展思考:如果解引用的使用也希望和箭头运算符一样,一步到位,又该如何实现

ThirdLayer tl(new MiddleLayer(new Data));
cout << (*tl).getData() << endl;

如下三种return的形式都可以实现。

内存分析

三层的结构比较复杂,我们可以通过内存图的方式进行分析。

ThirdLayer对象的创建

ThirdLayer tl(new MiddleLayer(new Data));

实际上的内存结构如图

创建和销毁的过程:

创建tl对象时,调用ThirdLayer的构造函数,在ThirdLayer构造函数的参数初始化过程中调用MiddleLayer的构造函数,在ThirdLayer构造函数的参数初始化过程调用Data的构造。

Data构造完才能完成MiddleLayer的指针数据成员初始化,MiddleLayer创建完毕,才能完成ThirdLayer的指针数据成员初始化。

tl销毁时,马上调用ThirdLayer的析构,执行delete _pml时,第一步调用MiddleLayer的析构,在这个过程中,会delete _pdata,会调用Data的析构函数。

由于构造函数打印信息语句只能在函数体中,所以呈现出如下结果

下面为测试代码,可以自行测试

#include<iostream>
using namespace std;
class Data {
public ://构造函数Data(){cout << "Data()" << endl;}Data(int x):_data(x){cout << "Data(int)" << endl;}int get()const { return _data; }~Data() { cout << "~Data()" << endl; }
private:int _data = 10;
};class middlelayer {
public:middlelayer(Data* p):_pdata(p){cout << "middlelayer(Data*)" << endl;}~middlelayer() {cout << "~middlelayer()" << endl;if (_pdata) {delete _pdata;_pdata = nullptr;}}Data * operator->(){return _pdata;}//要返回一个data对象,才可以用点来Data& operator* (){return *_pdata;}friend class thirdlayer;
private:Data* _pdata;
};class thirdlayer {
public:thirdlayer(middlelayer* ml):_pml(ml){cout << "thirdlayer(middlelayer *)" << endl;}~thirdlayer() {cout << "~thirdlayer()" << endl;if (_pml){delete _pml;_pml = nullptr;}}//返回middlelayer对象,因为middlelayer对象对->进行了重载middlelayer& operator ->(){return *_pml;}//1.一步一步解引用/*middlelayer& operator*(){return *_pml;}*///2.一步到位解引用Data& operator*(){//从thirdlayer出发只能得到middlelayer对象//由于middlelayer对象已经对解引用运算符进行了初始化进行过重载//所以可以直接通过对middlelayer对象解引用得到data对象//return *(*_pml);//return (*_pml).operator*();//从内存的角度//_pml存储的是middlelayer,通过middlelayer访问data的地址,但是要将thirdlayer声明为middlelayer的友元类才能访问私有成员return *((*_pml)._pdata);}
private:middlelayer* _pml;
};void test()
{//下面两行代码会出错,因为栈帧结束,ml会调用析构函数,所以ml管理的对象至少应该在堆上的空间/*Data d1;middlelayer ml( &d1);*///不建议这样使用,//因为如果手动的通过p1指针来回收堆上的Data对象空间//会出现double free的问题Data* p1 = new Data();cout << p1->get() << endl;cout << (*p1).get() << endl;middlelayer ml(p1);//delete p1;
}
void test1()
{Data* p1 = new Data();cout << p1->get() << endl;cout << (*p1).get() << endl;delete p1;//智能指针的雏形//利用局部对象的生命周期管理堆上的资源//ml是middlelayer类对象,不是指针//但是可以像原生的data* 指针一样使用箭头运算符和解引用运算符//访问data的成员//并且,不需要像原生的指针一样去手动调用回收堆上的data空阿金middlelayer ml(new Data());//为什么可以进行重载呢,因为middlelayer底层的原型就是data类型cout << ml->get() << endl;//如下是middlelayer使用箭头运算符访问data类成员函数的本质形式//ml对象调用operator->函数,返回值是一个Data*//编译器自动加上了一个->(原生的箭头运算符)cout << ml.operator->()->get() << endl;cout << (*ml).get() << endl;cout << ml.operator*().get() << endl;//本质形式//是不可以的,和上面原因是一样的,因为tl是指向在栈上的空间,但是函数栈帧销毁的时候会调用delete,会出现错误//thirdlayer tl(&ml);}void test2()
{//调用tl的构造函数在调用middlelayer的构造函数在调用Data的构造函数,当data构造完成,后middlelayer构造完成,tl才能构造完成//就和递归很像thirdlayer tl(new middlelayer(new Data()));//tl调用operator->函数,返回值是其管理的middlelayer对象//由于middlelayer类中已经有对->运算符进行了重载//所以middlelayer对象可以直接使用->运算符访问data类中的成员//本质上就是调用了middlelayer的operator->函数cout << (tl.operator->()).operator->()->get() << endl;cout << (tl.operator->())->get() << endl;cout << tl->get() << endl;//1.一步一步解引用//因为middlelayer类已经对*运算符进行了重载//所以对third对象解引用只需要得到一个middlelayer对象/*cout << ((tl.operator*()).operator*()).get() << endl;cout << (*(*tl)).get() << endl;cout << (*(tl.operator*())).get() << endl;*///2.一步解引用cout << (*tl).get() << endl;cout << (tl.operator*()).get() << endl;
}
int main()
{test2();return 0;
}
http://www.dtcms.com/wzjs/553538.html

相关文章:

  • 微信做淘宝优惠券但网站是怎么建设但xampp上传Wordpress
  • 关闭WordPress文章摘要朝阳区seo搜索引擎优化怎么样
  • 嘉兴手机网站公司网站是如何搭建的
  • 长沙网站制作公司推荐个人网页设计与制作教程
  • 拜博网站建设做视频网站是什么职业
  • 盗版系统网站怎么建立怎样做网站标题的图标
  • iis做外网站点html制作简单的网页
  • 网站设计需要多少钱wordpress站群主机
  • No家电网站建设crm系统流程图
  • 国内网站都要备案吗做品牌 需要做网站吗
  • 如何把网站上传到空间房屋装修公司
  • 网站建设竞价托管服务中国国家城乡建设部网站
  • 专业的网站建设公司电话网站开发实用技术知识点
  • 珠海建设工程网站做淘客网站需要营业执照吗
  • 改网站字体颜色代码公司网站域名续费一年多少钱
  • 直播网站开发方案ppt企业做网站设计
  • 桐庐建设局网站微信代运营协议
  • semen是什么意思百度seo优化排名
  • 建设进出口外贸网站青海商会网站建设公司
  • 啊里云服务器怎么做网站主页制作
  • 幸福宝推广app网站入口辽宁建设厅网站首页
  • 怎么自己做模板网站百度竞价排名公司
  • 纯html5网站wordpress当前分类下所有子分类
  • 怎么做自己的淘客网站做淘客网站
  • 网站建设规划设计任务书构建网站系统
  • 云南省建设厅网站处长阿里云的网站程序如何做
  • wordpress 返回主页seo是免费推广吗?
  • 租用网站的服务器洞口网站建设
  • 网站建设问卷调查表番禺建设网站公司
  • 减肥网站源码深圳华强北在哪个区