栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

从零开始学C++11新标准知识(内含大厂面试题100道)第三期

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

从零开始学C++11新标准知识(内含大厂面试题100道)第三期

今天学习一下变量的相关知识吧

首先什么是变量?

会变化的数据量?可以改变的数据?带着是什么,为什么的疑惑,我们今天学习一下变量的区别。

       变量是我们程序员打代码时候,很常见的一种数据量,变量来源于数学,是计算机语言中能储存计算结果或能表示值抽象概念。变量可以通过变量名访问。在指令式语言中,变量通常是可变的;但在纯函数式语言(如Haskell)中,变量可能是不可变(immutable)的。在一些语言中,变量可能被明确为是能表示可变状态、具有存储空间的抽象(如在Java和Visual Basic中);但另外一些语言可能使用其它概念(如C的对象)来指称这种抽象,而不严格地定义“变量”的准确外延。 百度百科给出这样的概念。------来源于百度百科

变量分为全局变量、局部变量、静态全局/局部变量这四种变量:

C++变量根据定义的位置的不同拥有不同的生命周期,或者说是作用域不同。

作用域又分为:全局作用域、局部作用域、语句作用域、类作用域、命名空间作用域和文件作用域。

那么从作用域上来看区别:

全局变量:全局变量具有全局作用域,全局变量只需在一个源文件中定义,就可以作用于所有的源文件。当然其他不包含全局变量定义的源文件需要用extern关键字再次声明这个全局变量。

静态全局变量:静态全局变量具有文件作用域,它与全局变量的区别在于,如果程序包含多个文件的话,它作用于定义它的文件里不能作用到其他文件里及被static关键字修饰过的变量具有文件作用欲。这样,即使两个不同的源文件都定义了相同的名字的静态全局变量,它们也是不同的变量。

局部变量:具有局部作用域。它是自动对象(auto),在程序运行期间不是一直存在,而是只在函数执行期间存在,函数的一次调用执行结束后,变量被撤销,其所占用的内存也被收回。

静态局部变量:具有局部作用域。它只被初始化一次,自从第一次被初始化直到程序运行结束都一直存在,它和全局变量的区别在于全局变量对所有的函数都是可见的,而静态局部变量只对定义自己的函数体始终可见。

从分配空间上看:

静态存储区:全局变量、静态局部变量、静态全局变量

栈:局部变量

解释一下:

静态变量和栈变量(存储在栈中的变量)、堆变量(存储在堆中的变量)的区别:静态 变量会被放在程序的静态数据存储区(.data 段)中(静态变量会自动初始化),这样可以在下一次调用的时候还可以保持原来的赋值。而栈变量或堆变量不能保证在下一次调用的时候依然保持原来的值。

静态变量和全局变量的区别:静态变量用static 告知编译器,自己仅仅在变量的作用范围内可见。

那么问题来了

全局变量定义在头文件中会怎么样?会出现什么问题?

      如果在头文件中定义全局变量,当该头文件被多个文件include时,该头文件中的全局变量就会被定义多次,导致重复定义,因此不能再头文件中定义全局变量。

      全局变量不能放在头文件中,但是全局常量可以,不在头文件中定义全局变量,可以声明,加extern, 然后在对应cpp中定义。

那么如何限制类的对象只能在堆上创建?如何限制对象只能在栈上创建?

C++中的类的对象分为静态建立和动态建立两种方式。

静态建立:由编译器为对象在栈空间上分配内存,直接调动类的构造函数创建对象。例如:A a;

动态建立:使用new关键字在堆空间上创建对象,底层首先调用operator new() 函数,在堆空间上寻找合适的内存并分配;然后,调用类的构造函数创建对象。例如:A *p = new A();

限制对象只能建立在堆上:

最直观的思想:避免直接调用类的构造函数,因为对象静态建立时,会调用类的构造函数创建对象。但是直接将类的构造函数设为私有并不可行,因为当构造函数设置为私有后,不能在类的外部调用构造函数来构造对象,只能用new来建立对象。但是由于new创建对象时,底层也会调用类的构造函数,将构造函数设置为私有后,那就无法在类的外部使用new创建对象了。因此,这种方法不可行。

解决方法一:

将析构函数设置为私有。静态对象建立在栈上,是有编译器分配和释放空间,编译器为对象分配内存空间的时候,会对类的非静态函数进行检查,即编译器会检查析构函数的访问权限。当析构函数设置为私有类的时候,编译器创建的对象就无法通过访问析构函数来释放对象的内存空间。因此,编译器不会在栈上为对象分配内存。

class
{
public:
      A(){}
      void destory{}
      {
          delete this;
      }
private:
      ~A()
      {
      }
};

这个方法产生的问题是用new创建的对象,通常会使用delete释放该对象的内存空间,但此时类的外部无法调用析构函数,因此类的方法体里面必须定义一个destory()函数,用来释放new创建的对象。

解决方法二:

析构函数设置为protected,并提供一个public的静态函数来完成构造,而不在类的外部使用new构造,原因是:类似于单例模式(后期介绍开发模式)也保证李在派生类中能够访问析构函数。通过调用create()函数在堆上创建对象。

class B
{
protected:
      A(){}
      ~A(){}
public:
      static A *create()
      {
            return new A();
       }
      void destory{}
      {
          delete this;
      }
};
限制对象只能建立在栈上:

将operator new() 设置为私有。

原因是当对象建立在堆上时,我采用new的方式进行建立,其底层会调用operator new() 函数,因此只有对这个函数权限进行限制,就能防止对象建立子在堆上。

class C 
{
private:
     void *operator new(size_t t){}  //函数的第一个参数和返回值为固定的
     void operator delete(void *ptr)//重载了new 就需要重载delete
     {
      }
public:
      A(){}
      ~A(){}
};
总结一下

创建对象的两种方式:堆创建(用new创建)、栈创建(一般创建)

限制对象只能堆创建:

可以在对象外面使用new创建:析构函数设置为私有。

存在问题:

(1). 无法直接在类外部delete释放对象。

(2).析构函数定义成虚函数时无法在子类中重写(解决:析构函数设为protected)。

不在对象外使用new创建:将构造函数和析构函数全部设为protected通过调用成员函数动态创建和删除。

1和2本质上是同一种方法:将构造函数或析构函数(分别或同时)设为private或protected.

限制对象只能栈创建:

重载operator new()和operator delete()为private。

好啦,以上就是今天所学到的第一个C++大厂面试知识点,感兴趣的小伙伴欢迎评论区留言、点赞、转发。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/971225.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号