设计一个C++类,要求该类只能在栈(堆)上创建或者只有一个对象

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xiao3404/article/details/86501333

类只能在栈上创建

我们知道一个对象可在堆上创建或者栈上创建,c++中创建一个堆对象需要使用new运算符才可以,因为malloc不会调用构造和析构函数。因此想要达到该类只能在栈上创建,需要屏蔽new/delete运算符

我们将new/delete设置为private属性,我们在类外就无法调用该运算符,也就达到了这个类只能在栈上创建的效果。

//如何设计类只能建立在栈
class CClassInstanceStack
{
public:
    CClassInstanceStack()
    {
        std::cout << "call construct function\n";
    }

    ~CClassInstanceStack()
    {
        std::cout << "call destruction function\n";
    }

    void print_log()
    {
        std::cout << "call print log\n";
    }

    /**/
    //new 运算符是private,外部禁止调用  因此该类只能在栈上创建
    //重载了new运算符也需要重载delete运算符
private:

    void* operator new(std::size_t count){}

    void* operator new[](std::size_t count){}

    void operator delete[]( void* ptr ){}

    void operator delete( void* ptr ){}
};

/*类的使用*/
//无法访问 operate new或者new[]运算符
//build error
CClassInstanceStack* parrStack = new CClassInstanceStack[10];

//build error
CClassInstanceStack* pStack = new CClassInstanceStack;

//build ok
CClassInstanceStack  stack;
stack.print_log();

类只能在堆上创建

同理,一个类对象只能在堆上创建,那么对外只能提供new运算符接口,而构造函数或者析构函数至少有一个需要时私有的。因为我们在栈上创建对象时,需要调用构造函数,析构时会调用析构函数,屏蔽其中之一,栈上创建对象,编译器就能告警和编译异常。这类设计如下:

/*
   想要达到只能在堆上创建对象,其设计要求如下:
   1.该类的构造函数或者析构函数至少有一个是private属性
   2.提供一个创建对象接口,用于类内部创建堆对象
   3.提供堆对象销毁函数,这个非必须,需要看析构是否public属性
*/
class COnlyHeap
{
private:
    COnlyHeap():m_data(0){}
    ~COnlyHeap(){}

public:
    static COnlyHeap* CreateObj()
    {
        return new (std::nothrow) COnlyHeap;
    }

    static void DestroyObj(COnlyHeap* &pInstance)
    {
          if (NULL != pInstance)
          {
              delete pInstance;
              pInstance = NULL;
          }
    }

    int m_data;
};

//类的使用
COnlyHeap OnlyHeap;//build error

COnlyHeap* pOnlyHeap = COnlyHeap::CreateObj();
if (NULL != pOnlyHeap)
{
    pOnlyHeap->m_data = 10;
}

//需要手动释放对象,否则内存泄漏,不易维护
if (NULL != pOnlyHeap)
{
    COnlyHeap::DestroyObj(pOnlyHeap);
}

类只能一个对象

对于一个类只能创建一个对象,对应的就是设计模式当中的单例模式,单例模式关键点有以下:

  1. 构造函数和析构函数为private属性
  2. 全局唯一的访问点为public属性
  3. 为了使用方便,增加一个GC辅助类,用于释放资源。

这个类设计如下:

//类只能在堆上实例化
//1、如何设计类只能建立在堆上&单例模式只有一个模式
class CClassInstanceHeap
{
private:
    CClassInstanceHeap(){}
    ~CClassInstanceHeap(){}
public: 
    static CClassInstanceHeap* GetInstance()
    {
        return m_pIns;
    }

    void print_log()
    {
        std::cout << "print log by instance\n";
    }

private:
    // 是CClassInstanceHeap的辅助类,用于资源的释放
    class GC
    {
    public:
        GC()
        {
            std::cout << "gc construct \n";
        }

        ~GC()
        {
            //析构时释放资源
            std::cout << "gc delete instance \n";
            if (m_pIns != NULL)
            {
                delete m_pIns;
                m_pIns = NULL;
            }
        }
    };
    
private:
    static  CClassInstanceHeap* m_pIns;
    static  GC m_gc;
};
//类外初始化静态变量
//懒汉式 避免了多线程竞争问题   
//对象的初始化
CClassInstanceHeap*  CClassInstanceHeap::m_pIns  = new CClassInstanceHeap;
CClassInstanceHeap::GC CClassInstanceHeap::m_gc;

//main函数
//具有垃圾回收功能
CClassInstanceHeap::GetInstance()->print_log();

//运行结果
gc construct
print log by instance
gc delete instance

以上就是类设计当中,比较特殊的三种情况了,欢迎大家一起交流!

猜你喜欢

转载自blog.csdn.net/xiao3404/article/details/86501333