C++(4)/new delete & static & this指针 & 全局函数和成员函数

  • new & delete
    在软件开发过程中,常常需要动态地分配和撤销内存空间,例如对动态链表中结点的插入与删除。在C语言中是利用库函数malloc和free来分配和撤销内存空间的。C++提供了较简便而功能较强的运算符new和delete来取代malloc和free函数。
    既然有了malloc和free为什么C++还要引入new和delete呢?主要有两点考虑

    • new和delete 是operator;malloc和free是function。一个开销小一个开销大,当需要经常在堆上开辟和释放内存时,程序的执行效率明显不同。
    • new和delete能够调用构造函数和析构函数开辟和释放对象;而malloc和free想要对类与对象进行操作必须写全套,否则就有内存泄漏的风险。
      写个程序,对比一下new和delete;malloc和free的使用。

      
      #include <iostream>
      
      
      using namespace std;
      
      class Temp{
      private:
          int m_a;
          int m_b;
          int m_c;
      public:
          Temp(int a, int b, int c) :m_a(a), m_b(b), m_c(c){
              cout << "construct"<<endl;
          }
          Temp(const Temp & t){ 
              m_a = t.m_a; m_b = t.m_b; m_c = t.m_c; 
              cout << "construct" << endl;
          }
          void setT(int a, int b, int c){ 
              m_a = a; m_b = b; m_c = c; 
              cout << "set the value of t" << endl;
          }
          void printT(){ cout << "a: " << m_a << " b: " << m_b << " c: " << m_c << endl; }
          ~Temp(){ cout << "destruct" << endl; }
      };
      
      
      
      int main(){
      
          //C风格的动态内存分配
          //1. 变量
          int * p = (int*)malloc(sizeof(int));
          *p = 100;
          cout << *p << endl;
          if (p != NULL){
              free(p);
          }
          cout << "---------------------" << endl;
          //2. 数组
          int *pp = (int*)malloc(sizeof(int)* 10);
          for (int i = 0; i < 10; i++){
              pp[i] = i;
          }
          for (int i = 0; i < 10; i++){
              cout << pp[i] << " ";
          }
          cout << endl;
          if (pp != NULL){
              free(pp);
          }
          cout << "---------------------" << endl;
          //3. 二维数组
          /*
          先开辟一个二级指针指向多个一级指针
          然后对每个一级指针开辟一块内存空间。
          */
          int ** ppp = (int **)malloc(sizeof(int *)* 10);
          for (int i = 0; i < 10; i++){
              ppp[i] = (int *)malloc(sizeof(int)* 2);
              ppp[i][0] = i + 1;
              ppp[i][1] = i + 2;
          }
          for (int i = 0; i < 10; i++){
              cout << *ppp[i] << " " << *(ppp[i] + 1) << endl;
          }
          for (int i = 0; i < 10; i++){
              if (ppp[i] != NULL){
                  free(ppp[i]);
              }
          }
          free(ppp);
          cout << "---------------------" << endl;
      
          //4. 开辟一个对象
          Temp * t = (Temp *)malloc(sizeof(Temp));
          t->setT(1, 2, 3);
          t->printT();
          if (t != NULL){
              free(t);
              cout << "clear the value of t" << endl;
          }
          cout << "---------------------" << endl;
      
      
      
          //C++风格 new delete
          //1. 变量
          int *p_ = new int(10);
          cout << "C++: p:" << *p_ << endl;
          if (p_ != NULL){
              //free(p_);
              delete p_;
          }
          cout << "---------------------" << endl;
      
      
          //2. 数组
          int *pp_ = new int[10];
          for (int i = 0; i < 10; i++){
              pp_[i] = i;
          }
          for (int i = 0; i < 10; i++){
              cout << pp_[i] << " ";
          }
          cout << endl;
          if (pp_ != NULL){
              //free(pp_);
              delete[] pp_;
          }
      
          cout << "---------------------" << endl;
      
          //3.二维数组
          int (*ppp_)[5]= new int[5][5];
          for (int i = 0; i < 5; i++){
              for (int j = 0; j < 5; j++){
                  ppp_[i][j] = i + j;
              }
          }
          for (int i = 0; i < 5; i++){
              for (int j = 0; j < 5; j++){
                  cout << ppp_[i][j] << " ";
              }
              cout << endl;
          }
          if (ppp_ != NULL){
              delete[] ppp_;
      
          }
      
          cout << "---------------------" << endl;
          //4. 对象
          Temp * t_ = new Temp(1, 2, 3);
          t_->printT();
          if (t_ != NULL){
              delete t_;
          }
          cout << "---------------------" << endl;
          return 0;
      }
      

    有几个点想提一下:

    • malloc和free new和delete除了上述两点可以看做是”一样”的。我们可以用free释放new分配的内存空间。使用delete释放new分配的内存空间。但是这种写法是不符合规范的。
    • new分配内存空间赋初值使用();分配多个空间使用[num];delete中释放多个内存空间使用delete[],其他情况使用delete即可。
    • 分配内存之后一定要初始化;释放内存前一定要判断指针是否为空。

  • static
    将C++中的static之前先回顾一下C中的static。
    在C中:

    • static修饰局部变量表示在全局区的静态区中开辟一块内存空间。
    • static修饰全局变量时,表示该变量只能在该文件中被使用,不能被别的文件访问。
    • static修饰函数时,表示该函数只能在该文件中被使用,不能被别的文件访问。

    在C++中,上述规则同样试用。但是在C++中,我们多了类的概念,下面就来讲一讲C++类中static的用法。

    C++类中的static主要有两种用法:

    1. 静态成员变量
      静态成员变量是为了数据共享而创造的概念。C++中static成员变量属于类(当然能够被类实例化的对象所调用),但是却不和类存储在一起(static成员变量存放在全局区的静态区)。
      定义在类中的static变量和定义在类外的static变量有什么区别呢?我们打个比方,定义在类中的静态成员变量就想是被类”冠名了”一样static属于类,在使用静态成员变量之前要加上冠名商,也就是类名的名字来使用。即静态成员变量的命名空间属于类。

      //声明
      static 数据类型 成员变量;
      //在类的内部
      
      //初始化
      数据类型 类名::静态数据成员=初值;
      //在类的外部
      
      //调用
      类名::静态数据成员
      类对象.静态数据成员
      

      用处:

      • 最直接的一个例子:定义一个box,要求所有box高度一样。这样只需要定义一个可以共享的变量height就解决问题了。
      • 仓库进货模型可以使用静态成员变量来解决。定义一个仓库类,构造函数中,写入进货的数量和重量。存放在静态成员变量中;析构函数中写出货的数量和重量。结合链表实现构造和析构,这样通过两个全局变量就能够管理仓库中货物的数量和重量。同样的例子还有求学生平均分。
    2. 静态成员函数

      • 定义和调用

        //声明
        static  函数声明
        //调用
        类名::函数调用
        类对象.函数调用
      • tips
        1. 静态成员函数的意义,不在于信息共享,数据沟通,而在于管理静态数据成员, 完成对静态数据成员的封装。
        2. 静态成员函数只能访问静态数据成员。原因:非静态成员函数,默认传入this指针。而静态成员函数属于类,而不属于对象,没有 this 指针。
    3. 从静态成员变量看类中属性和方法的内存分配

      注意:为了方便描述,下列叙述并不严谨,但表达的意义理解就好。

      类中普通成员变量和类一起存储。
      类中静态成员变量存储在全局区的静态区。和类中对象的存储分离。
      类中成员函数无论是否静态均与类分离存储。我们知道函数名表示一个指针,占4个字节。尽管如此,函数全部存在代码区,不占用类的内存。

      那为什么C++这么对类呢?
      因为C++的编译器把类翻译成结构体和函数的组合。
      class-struct

总结: static把局部变量变成全局变量,把全局变量变成锁定的变量。
static把类中的成员变成公有的成员,把类中的方法去掉this指针,只能访问类中静态成员变量。


  • this指针

    • 考虑一个问题:
      我们知道类中的成员函数都存放在代码段,只存储一份。那么不同的对象调用同一个函数得到不同的输出。但是该函数没有看到有”输入的参数”,那么不同的输出是怎么来的呢?

    • this的作用
      this指针解决的第一个问题就是成员函数如何无条件访问类中属性。
      this指针解决的第二个问题就是名字冲突的问题。
      this指针解决的第三个问题是成员函数如何返回调用对象自身。

    • this指针的本质
      this指针本质上是指向当前对象的一个常指针,每个对象都会有一个this指针。在对象调用成员函数时,会隐式的传入当前对象的地址为this指针初始化。如果希望通过this指针访问类中属性不被修改,可以使用const。具体如下:

      //成员函数如何定义才能将this指针升级为指向常量的常指针?
       void test() const {}  //在小括号和花括号之间加上const
  • 全局函数和局部函数的互换
    我们知道全局函数没有this指针传入当前对象;而局部函数有this指针隐式传值,所以两者如果互换,参数要做转换。

    这里将一个C++编程的原则。我们知道C++是基于值传递的。值传递就要进行拷贝。所以我们往往使用指针和引用避免拷贝。在面对对象的时候更是这样。这个时候局部函数的优势就出来了。使用全局函数,如果想要输出,不可避免的要发生拷贝,且不能直接返回被操作的对象,因为没有this指针。当然如果要强行用全局函数实现也可以,但是跟成员函数比肯定会麻烦不少。使用成员函数返回*this就把当前对象返回了;返回值类型定义为引用,这样就避免了拷贝。并且是匿名引用,使用完毕全部都会被销毁,也不占用内存空间。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值