不止于在栈上或堆上创建对象

从真实开发经历来讲,只允许在栈上或者堆上创建对象的情况比较少,当然也有可能是我用C++开发的时间并不长。
  

Case 1 只在栈上创建

1、不考虑子类

  C++使用new来申请对象空间,要想只让其在栈上申请,要么让其在堆上无法申请,要么让其无法释放。
  所以,让new操作符或者delete操作符无法使用就可以了。

  class Base
  {
  public:
  protected:
  private:
      void* operator new(size_t t) {};
      void operator delete(void *) {};
  };
  int main()
  {
      Base* b = new Base;
      Base d;
      return 0;
  }

  此时new操作会报一个语法错误(IDE为vs2015)这里写图片描述,这里我们还可以看到编译器首先去检查的是操作符delete而不是new,所以只需要让操作符delete无法使用就足够了。
  
  在C++11以后的标准,我们还可以用delete(当然不是释放内存用的)关键字来实现。

  class Base
  {
  public:
       void operator delete(void *) = delete;
  protected:
  private:
  };
  int main()
  {
      Base* b = new Base;
      Base d;
      return 0;
  }

  此时操作符的编译错误是不止于在栈上或堆上创建对象_第1张图片
  这里还有一个有意思的地方,可以看到两个new的声明是不一样的,而第二个还有一个+3重载,这个问题留着下回再讲:-)。

2、考虑子类

  由于基类已经无法在堆上申请所需空间,对于子类而言,由于其先要为基类申请空间。因此,子类必然不能在堆上创建对象。

Case 2 只在堆上申请

1、不考虑子类

  要想只在堆上申请,当然只有让其不能自动在栈上创建对象,所以可以让对象无法执行构造函数或者析构函数。

    class Base
  {
  public:
  protected:
  private:
      Base(){};
      ~Base(){};
  };
  int main()
  {
      Base b;
      return 0;
  }

  这时候,申明一个对象会报错这里写图片描述。注意这儿是先检查构造函数,而不是析构函数,跟new、delete可不一样。
  
  当然,此时也不能直接使用new操作符在堆上申请,所以我们取巧一下。

    class Base
  {
  public:
        static Base* create(size_t t = 1)
        {
            return new Base[t];
        }
        static void destroy(Base* b)
        {
            delete[] b;
        }
  protected:
  private:
        Base(){};
        ~Base(){};
  };
  int main()
  {
        Base* d = Base::create(10);
        Base::destroy(d);
        return 0;
  }

  在用new创建对象的时候最好用申请数组的方式,同时将长度参数默认设置为1,那样会更具有通用性一些。
  
  注意此时不能用delete关键字去禁用构造函数或者析构函数,因为在创建对象的时候,无论如何总要调用构造函数,在释放对象的时候,总要调用析构函数。

2、考虑子类

  如果是要让子类不受基类影响,可以把构造函数或者析构函数设为保护对象,对于子类而言,基类的保护成员是可以访问的。

    class Base
    {
    public:
        static Base* create(size_t t = 1)
        {
            return new Base[t];
        }
        static void destroy(Base* b)
        {
            delete[] b;
        }
    protected:
        ~Base(){};
    private:
    };

    class Derive :public Base
    {
    };

  int main()
  {
        Base* b = Base::create(10);
        Base::destroy(b);
        Derive* d = new Derive;
        delete d;
        Derive d2;
        return 0;
  }

  如果是要像基类一样只允许在堆上创建对象,那就得像基类一样再实现一遍create,destroy咯。

    class Base
    {
    public:
        static Base* create(size_t t = 1)
        {
            return new Base[t];
        }
        static void destroy(Base* b)
        {
            delete[] b;
        }
    protected:
        ~Base(){};
    private:
    };

    class Derive :public Base
    {
    public:
        static Derive* create(size_t t = 1)
        {
            return new Derive[t];
        }
        static void destroy(Derive* b)
        {
            delete[] b;
        }
    protected:
        ~Derive() {};
    };

  int main()
  {
        Derive* d = Derive::create(10);
        Derive::destroy(d);
        return 0;
  }

你可能感兴趣的:(C++/C)