【c++】【转】如何只在heap上创建对象,如何只在stack上建立对象?
http://www.cnblogs.com/chio/archive/2007/10/23/934335.html
http://blog.csdn.net/szchtx/article/details/12000867
在C++中,类的对象建立分为两种,一种是静态建立,如A a;另一种是动态建立,如A* ptr=new A;(ptr是栈上变量,指向堆中空间)这两种方式是有区别的。
静态建立一个类对象,是由编译器为对象在栈空间中分配内存,是通过直接移动栈顶指针,挪出适当的空间,然后在这片内存空间上调用构造函数形成一个栈对象。使用这种方法,直接调用类的构造函数。
动态建立类对象,是使用new运算符将对象建立在堆空间中。这个过程分为两步,第一步是执行operator new()函数,在堆空间中搜索合适的内存并进行分配;第二步是调用构造函数构造对象,初始化这片内存空间。这种方法,间接调用类的构造函数。
1、只能建立在堆上:(将构造函数、析构函数声明为private,然后将new、delete封装在静态成员函数中,通过静态成员函数的调用来实例化对象和销毁对象)
类对象只能建立在堆上,就是不能静态建立类对象,即不能直接调用类的构造函数。
容易想到将构造函数设为私有。在构造函数私有之后,无法在类外部调用构造函数来构造类对象,只能使用new运算符来建立对象。然而,前面已经说过,new运算符的执行过程分为两步,C++提供new运算符的重载,其实是只允许重载operator new()函数,而operator()函数用于分配内存,无法提供构造功能。因此,这种方法不可以。
当对象建立在栈上面时,是由编译器分配内存空间的,调用构造函数来构造栈对象。当对象使用完后,编译器会调用析构函数来释放栈对象所占的空间。编译器管理了对象的整个生命周期。如果编译器无法调用类的析构函数,情况会是怎样的呢?比如,类的析构函数是私有的,编译器无法调用析构函数来释放内存。所以,编译器在为类对象分配栈空间时,会先检查类的析构函数的访问性,其实不光是析构函数,只要是非静态的函数,编译器都会进行检查。如果类的析构函数是私有的,则编译器不会在栈空间上为类对象分配内存。
因此,将析构函数设为私有,类对象就无法建立在栈上了。代码如下:
class A
{
public:
A(){}
void destory(){delete this;}
private:
~A(){}
};
上述方法的一个缺点就是,无法解决继承问题。如果A作为其它类的基类,则析构函数通常要设为virtual,然后在子类重写,以实现多态。因此析构函数不能设为private。还好C++提供了第三种访问控制,protected。将析构函数设为protected可以有效解决这个问题,类外无法访问protected成员,子类则可以访问。
将析构函数声明为private,类的用户不能定义类对象,但是友元或类成员函数可以使用,为了防止友元或类成员函数使用,可以将析构函数只声明不定义,这样若类的用户定义类对象,编译时出错,成员函数或友元定义类对象,链接时出错,此处不用考虑友元和成员函数,只是要求类用户不能静态建立对象。
另一个问题是,类的使用很不方便,使用new建立对象,却使用destory函数释放对象,而不是使用delete。(使用delete会报错,因为delete对象的指针,会调用对象的析构函数,而析构函数类外不可访问)这种使用方式比较怪异。为了统一,可以将构造函数设为protected,然后提供一个public的static函数来完成构造,这样不使用new,而是使用一个函数来构造,使用一个函数来析构。代码如下,类似于单例模式:
class A
{
protected:
A(){}
~A(){}
public:
static A* create()//可以用类名来调用,非静态成员函数不能用类名调用
{
return new A();
}
void destory()
{
delete this;
}
};
2、只能建立在栈上
只有使用new运算符,对象才会建立在堆上,因此,只要禁用new运算符就可以实现类对象只能建立在栈上。将operator new()设为私有即可。代码如下:
class A
{
private:
void* operator new(size_t t){} // 注意函数的第一个参数和返回值都是固定的,new的参数是new的运算对象
void operator delete(void* ptr){} // 重载了new就需要重载delete
public:
A(){}
~A(){}
};
【c++】【转】如何只在heap上创建对象,如何只在stack上建立对象?的更多相关文章
- C++:在堆上创建对象,还是在栈上?
这篇文章来自于一次讨论:http://www.devbean.net/2013/01/qt-study-road-2-model-view/#comment-17532.关于究竟是在堆上还是在栈上创建 ...
- 解决JFinal多文件上传时只获取到第一个文件名
我的思路: 用户生成时随即生成一串随机字符作为该用户的文件上传目录,并保存该字符串到用户的某一字段.需要显示上传的附件时,遍历这个文件夹.上传时可把文件名设置为上传时间. 1.生成上传路径 可写在注册 ...
- C++中如何设计一个类只能在堆或者栈上创建对象,面试题
设计一个类,该类只能在堆上创建对象 将类的构造函数私有,拷贝构造声明成私有.防止别人调用拷贝在栈上生成对象. 提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建 注意 在堆和栈上创建对象都会调 ...
- 文件的上传(表单上传和ajax文件异步上传)
项目中用户上传总是少不了的,下面就主要的列举一下表单上传和ajax上传!注意: context.Request.Files不适合对大文件进行操作,下面列举的主要对于小文件上传的处理! 资源下载: 一. ...
- maven工程 java 实现文件上传 SSM ajax异步请求上传
java ssm框架实现文件上传 实现:单文件上传.多文件上传(单选和多选),并且用 ajax 异步刷新,在当前界面显示上传的文件 首先springmvc的配置文件要配置上传文件解析器: <!- ...
- 普通文件的上传(表单上传和ajax文件异步上传)
一.表单上传: html客户端部分: <form action="upload.ashx" method="post" enctype="mul ...
- 第一次使用Git上传本地项目到github上
对于程序原来说都听说过GitHub,GitHub有许多开源的的项目和一些前沿的技术.因为自己在刚刚开始使用Git把自己写的一些小dome放到GitHub上遇到许多的坑,这么长时间过去了,想对第一次使用 ...
- Plupload 上传详细讲解,Plupload 多实例上传,Plupload多个上传按钮--推荐使用
今天帮朋友解决 Plupload 上传的问题,查了很多资料,资料还是挺全的,但是有点零零散散的,故整理好,合并发出来. 本教程包括: Plupload 上传详细讲. Plupload 多实例上 ...
- toLocaleTimeString()方法在IE和谷歌浏览器上 根据本地时间格式,把 Date 对象的时间部分(不含日期)转换为“时间字符串”存在区别
这两天修改一个bug,发现一个问题: toLocaleTimeString()方法在IE和谷歌浏览器上 根据本地时间格式,把 Date 对象的时间部分(不含日期)转换为“时间字符串”存在区别.方法原 ...
随机推荐
- ios开发介绍
iOS开发概述 •什么是IOS •什么是IOS开发 •为什么要选择IOS开发 •学习IOS开发的准备 1.什么是iOS •iOS是一款由苹果公司开发的操作系统(OS是Operating Sys ...
- CAD交互绘制带周长面积的矩形框(com接口)
主要用到函数说明: _DMxDrawX::DrawLine 绘制一个直线.详细说明如下: 参数 说明 DOUBLE dX1 直线的开始点x坐标 DOUBLE dY1 直线的开始点y坐标 DOUBLE ...
- python闭包浅见
1.个人理解定义:在一个函数A内部定义一个函数B,并在定义的内部函数B内对这个函数A的变量进行引用,那么内部函数B就是闭包. 2.特性:在内部函数内不能对A函数的变量进行更改 (但是可以将其封装到一个 ...
- 瀑布流布局js
<!DOCTYPE html><html><head> <meta http-equiv="Content-Type" content=& ...
- org.dom4j.DocumentException
在使用soapui测试webservice接口的时候如果需要传入xml格式的参数 这么写是不对的,会报错org.dom4j.DocumentException: Error on line 1 of ...
- KBE_运作流程
图片来自官方手册:Switch Fabric:交换机网络,根据网络环境的不同而不同,根据用户自己的情况进行配置,不属于引擎范畴. 运作流程 Client连接Loginapp通过API连接,如下示例: ...
- [Python3网络爬虫开发实战] 1.6.2-Tornado的安装
Tornado是一个支持异步的Web框架,通过使用非阻塞I/O流,它可以支撑成千上万的开放连接,效率非常高,本节就来介绍一下它的安装方式. 1. 相关链接 GitHub:https://github. ...
- 零基础入门学习Python(26)--字典:当索引不好用时2
知识点 删除字典元素 能删单一的元素也能清空字典,清空只需一项操作. 显示删除一个字典用del命令,如下: >>> dict1 = {'a':1,'b':2,'c':3} >& ...
- 升级PHP7操作MongoDB
前言 使用 PHP+MongoDB 的用户很多,因为 MongoDB 对非结构化数据的存储很方便.在 PHP5 及以前,官方提供了两个扩展,Mongo 和 MongoDB,其中 Mongo 是对以 M ...
- django-2 models
一个model 对应DB的一张表 models 以类的形式表现: 一些字段.数据的一些行为 对类.类的对象 操作,无需写SQL = > object relation mapping ORM ...