如何限制C++类的对象只能建立在堆上或栈上

来源:互联网 发布:记事本软件无弹窗下载 编辑:程序博客网 时间:2024/05/21 17:48
C++中,类的对象建立分为两种,一种是静态建立,如A a; 另一种是动态建立,如 A *ptr = new A;
    静态建立一个类对象,是由编译器为对象在栈空间中分配内存,是通过直接移动栈顶指针,挪出适当的空间,然后在这片内存空间上调用构造函数形成一个栈对象。使用这种方法,直接调用类的构造函数。
    动态建立一个类对象,是使用new运算符将对象建立在堆空间中。这个过程分为两步:第一步,执行operator new()函数,在堆空间中搜索合适的内存并进行分配;第二步,调用构造函数构造对象,初始化这片内存空间;第三步,返回正确的指针。这种方法,间接调用类的构造函数。

一、只能建立在堆上
方法1:将类的析构函数设为private
方法2:将构造和析构函数设为protected,定义public static函数创建对象,定义public函数删除对象。[推荐使用]
    类对象只能建立在堆上,就是不能静态建立类对象,即不能直接调用类的构造函数。容易想到将构造函数设为私有。在构造函数私有之后,无法在类外部调用构造函数来构造类对象(即无法静态建立),只能使用new运算符来建立对象。C++提供new运算符的重载,但new函数只能用于分配内存,无法提供构造功能,因此这种方法不可行。[ 因为静态建立/动态建立一个类对象时,会直接/间接调用类的构造函数,所以将构造函数设为私有的方法不可行。]
    编译器管理了对象的整个生命周期,当对象建立在栈上时,由编译器分配内存空间,调用构造函数来构造栈对象。当对象使用完后,编译器调用析构函数来释放栈对象所占的空间。当编译器为类对象分配栈空间时,会先检查类的析构函数的访问性(不光是析构函数,只要是非静态的函数,编译器都会检查)。如果类的析构函数是私有的,则编译器不会在栈空间上为类对象分配内存。
class HeapOnly
{
public:
    HeapOnly(){}
    void destory(){delete this;}
private:
    ~HeapOnly(){}
};

int main()
{
    //HeapOnly objectHeapOnly;    // compile error
    HeapOnly *ptrHO = new HeapOnly;
    ptrHO->destory();

    return 0;
}
使用HeapOnly objectHeapOnly; 创建类对象时,编译阶段会报错。
$ g++ classObject.cpp
classObject.cpp: In function ‘int main()’:
classObject.cpp:7: error: ‘HeapOnly::~HeapOnly()’ is private
classObject.cpp:13: error: within this context
    上述代码代码有两个问题:
(1)无法解决继承问题。如果HeapOnly作为多态基类,则析构函数通常要设为virtual,然后在子类重写,以实现多态。因此析构函数不能设为private。
将析构函数设为protected可以有效解决这个问题,类外无法访问protected成员,子类可以访问。
(2)使用new创建一个类实例,却用destory函数释放对象,而不能使用delete删除对象。因为delete对象指针,会调用对象的析构函数,而析构函数在类外不可访问。
将构造函数设为protected,提供一个public的static函数来完成构造[静态成员函数可以通过类名直接访问](不使用new)。使用一个函数来构造,使用另一个函数来析构。
#include <iostream>

class HeapOnly
{
protected:
    HeapOnly(){}
    ~HeapOnly(){}
public:
    static HeapOnly* create()
    {
        return new HeapOnly();
    }
    void destory()
    {
        delete this;
    }
    void printLog()
    {
        std::cout<<"call printLog"<<std::endl;
    }
};

int main()
{
    HeapOnly *ptrHO = HeapOnly::create();
    ptrHO->printLog();
    ptrHO->destory();

    return 0;
}

二、只能建立在栈上
方法:将operator new()函数设为private
    只有使用new运算符,对象才能建立在堆上,因此禁用new运算符就可以实现类对象只建立在栈上。
class StackOnly
{
public:
    StackOnly(){}
    ~StackOnly(){}
private:
    void* operator new(size_t t){}
    void operator delete(void* ptr){}
};


参考:
http://blog.csdn.net/szchtx/article/details/12000867
阅读全文
0 0
原创粉丝点击