相关文章推荐
失落的汽水  ·  Building a Real-Time ...·  1 月前    · 
讲道义的脸盆  ·  解析或序列化 XML - ...·  3 周前    · 
跑龙套的单杠  ·  分享6个对象数组去重的方法开发者社区·  3 周前    · 
纯真的炒饭  ·  MongoDB数据库中更新与删除数据 - ...·  2 周前    · 
体贴的红金鱼  ·  在 Office 加载项中使用 ...·  2 周前    · 
英姿勃勃的松鼠  ·  Date() 构造函数 - ...·  1 年前    · 
淡定的斑马  ·  “耗尽”人类语言:ChatGPT还有多少数据 ...·  2 年前    · 
高大的凉茶  ·  onlyoffice+vue集成_onlyo ...·  2 年前    · 
痴情的键盘  ·  ”System.InvalidOperati ...·  2 年前    · 
踢足球的围巾  ·  archlinux下,dwm/i3下截图解决 ...·  2 年前    · 
Code  ›  explicit关键字,lambda表达式,static关键字,const关键字,inline关键字,define宏_干干干就完了的博客
初始化 构造函数 lambda const
https://blog.csdn.net/qq_36553387/article/details/114819358
腼腆的炒粉
2 年前
  • explicit的作用(如何避免编译器进行隐式类型转换)
  • lambda表达式
    • 值捕获
    • 引用捕获
    • 隐式捕获
  • static
    • 静态函数
    • 静态变量的内存分配
    • static在类中使用的注意事项
    • static静态成员函数
      • 为什么static成员函数不能为const函数
    • 静态成员函数可以是虚函数么?
    • static全局变量和普通全局变量的区别
  • const作用及用法
    • 作用:
    • 在类中的用法:
      • const成员变量
      • const成员函数
    • define和const的区别
      • 区别:
      • const的优点:
    • define和typedef的区别
    • inline作用及其使用方法
      • 作用:
      • 使用方法:

      explicit的作用(如何避免编译器进行隐式类型转换)

      作用:声明类构造函数是显式调用的,而非隐式调用, 可以阻止调用构造函数时进行隐式转化。只可用于修饰单参数的构造函数,因为无参构造函数和多参构造函数本身就是显式调用的 。

      隐式转换:

      #include <iostream>
      #include <cstring>
      class A{
      public:
          int var;
          A(int tmp)
      		var = tmp;
      int main(){
          A ex = 10; //发生了隐式转换
          return 0;
      

      上述代码,A ex = 10在编译时,进行了隐式转换,将10转换成了A类型的对象,然后将该对象赋值给了ex。

      为了避免隐式转换,可用explicit关键字进行声明。

      explicit构造函数只能用于直接初始化

      #include <iostream>
      #include <cstring>
      using namespace std;
      class A{
      public:
      	int var;
      	explicit A(int tmp)
      		var = tmp;
      int main(){
      	A ex(100);
      	A ex1 = 10; //出错,不能使用类型转换构造函数
      	return 0;
      

      lambda表达式

      lambda表达式具有如下形式

      [capture list](parameter list)->return type { function body }
      

      其中,capture list(捕获列表)是一个lambda所在函数中定义的局部变量的列表。return type,parameter list和function body与任何普通函数一样,分别表示返回类型,参数列表和函数体。与普通函数不同,lambda必须使用尾置返回来指定返回类型

      当定义一个lambda时,编译器生成一个与lambda对应的新的类类型。可以这样理解,当向一个函数传递一个lambda时,同时定义了一个新类型和该类型的一个对象,传递的参数就是此编译器生成的类类型的未命名对象。默认情况下,从lambda生成的类都包含一个对应该lambda所捕获的变量的数据成员,类似任何普通类的数据成员,lambda的数据成员也在lambda对象创建时被初始化。

      采用值捕获的前提是变量可以拷贝,与参数不同,被捕获的变量的值是在lambda创建时拷贝,而不是调用时拷贝。

      void fcn1()
          size_t v1 = 42; //局部变量
          auto f = [v1]{ return v1; };
          v1 = 0;
          auto j = f(); //j为42,f保存了我们创建它时v1的拷贝;
      
      void fcn2(){
      	size_t v1 = 42;  //局部变量
      	auto f2 = [&v1]{ return v1; };
      	v1 = 0;
      	auto j = f2(); //j为0;f2保存了v1的引用,而非拷贝
      

      一个以引用方式捕获的变量与其他任何类型的引用的行为类似,当我们在lambda函数体内使用此变量时,实际上使用的是引用所绑定的对象。

      引用捕获和返回引用有着相同的问题和限制。如果我们采用引用方式捕获一个变量,就必须确保被引用的对象在lambda执行的时候是存在的。lambda捕获的都是局部变量,这些变量在函数结束后就不复存在了。

      为了指示编译器推断捕获列表,应在捕获列表中写一个&或=。&告诉编译器采用捕获引用方式,=则表示采用值捕获方式。

      如果我们希望对一部分变量采用值捕获,对其他变量采用引用捕获,可以混合使用隐式捕获和显式捕获。当我们混合使用隐式捕获和显式捕获时,捕获列表中的第一个元素必须是一个&或=。当混合使用隐式捕获和显式捕获时,显式捕获的变量必须使用与隐式捕获不同的方式。

      static

      作用:定义静态变量,静态函数。

      • 保持变量内容持久:static作用于局部变量,改变了局部变量的生存周期,使得该变量存在于定义后之后程序运行结束的这段时间。
      • 默认初始化为0,包括未初始化的全局静态变量和局部静态变量。
      #include <iostream>
      using namespace std;
      int func(){
          static int var = 1;
          var += 1;
          return var;
      int main(){
          for(int i = 0; i < 10; i++)
              cout << func() << " "; // 2 3 4 5 6 7 8 9 10 11
          return 0;
      
      • 隐藏:static作用于全局变量和函数,改变了全局变量和函数的作用域,使得全局变量和函数只能在定义它的文件中使用,在源文件中不具有全局可见性。(注:普通全局变量和函数具有全局可见性,即其他的源文件也可以使用)。
      • static作用于类的成员变量和类的成员函数,使得类变量和类成员函数和类有关,也就是说可以不定义类的对象就可以通过类访问这些静态成员。注意:类的静态成员函数中只能访问静态成员变量或者静态成员函数,不能将静态成员函数定义成虚函数。
      #include <iostream>
      using namespace std;
      class A{
      private:
          int var;
          static int s_var; //静态成员变量
      public:
      	void show(){
              cout << s_var++ << endl;
          static void s_show(){
              cout << s_var <<endl;
              //cout << var << endl; 静态成员函数不能调用非静态成员变量,不能使用this.var
              //show(); 静态成员函数不能调用非静态成员函数。无法使用this.show()
      

      在函数返回类型前加static,函数即被定义位静态函数,静态函数只能在声明它的文件当中可见,不能被其他文件所用,换句话说,只可以在.cpp文件中使用,不会同其他.cpp中的同名函数引起冲突。
      所以不要在头文件中声明static全局函数,这样没有意义。

      静态变量的内存分配

      静态变量内存的分配是在程序执行之前,编译时进行内存分配的。

      在编译时期分配内存和初始化变量意味着程序不必跟踪函数是否调用以及变量是否初始化。具有常量初始值的局部静态变量在本质上与全局变量相同,只是名称仅在该函数的范围内有效。

      如果在一个函数中有一个很大的局部静态变量,并且不像为该变量浪费内存,请使用局部静态指针而不是局部静态变量。

      局部静态变量的生命周期从程序流第一次遇到局部静态变量的声明时开始,在程序终止时结束。

      static在类中使用的注意事项

      • 静态成员变量是在类内进行声明,在类外进行定义和初始化,在类外进行定义和初始化的时候不可以出现static关键字和private,public,protected访问规则。
      • 静态成员变量相当于类域中的全局变量,被类的所有对象所共享,包括派生类的对象。
      • 静态成员变量可以作为成员函数的参数,而普通成员变量不可以。
      #include <iostream>
      using namespace std;
      class A{
      public:
          static int s_var;
          int var;
          void fun1(int i = s_var); //正确,静态成员变量可以作为成员函数的参数
          void fun2(int i = var);   //error 非静态成员变量不可以作为函数的参数
      
      • 静态数据成员的类型可以是所属类的类型,而普通数据成员的类型只能是该类类型的指针或引用。
      #include <iostream>
      using namespace std;
      class A{
      public:
      	static A s_var; //静态数据成员
          A var;
          A *p;  //正确,指针
          A& varl;  //正确,引用
      

      static静态成员函数

      • 静态成员函数不能调用非静态成员变量或者非静态成员函数,因为静态成员函数没有this指针,静态成员函数作为类作用域的全局函数。
        • 如果要在静态函数中访问类的动态成员(包括成员函数和成员变量),有下面两种方式:
          • 通过类的静态对象来调用。
          • 将类的对象作为参数传递给该静态函数,然后在静态函数中引用这个对象,并调用动态方法。
      • 静态成员函数不能声明成虚函数(virtual),const函数和volatile函数。

      为什么static成员函数不能为const函数

      • 当声明一个非静态成员函数为const时,对this有影响。对于一个test类的const修饰的成员函数,this指针相当于test const* const,而对于非const成员函数,this指针相当于test* const。而static成员函数没有this指针,所以使用const来修饰static成员函数没有任何意义。

      静态成员函数可以是虚函数么?

      静态成员函数不能被声明为virtual函数。
      因为

      • static成员不属于任何类对象或类实例,所以即使给此函数加上virtual也没有任何意义
      • 静态与非静态成员函数有一个主要的区别,就是静态成员函数没有this指针,也就没有办法访问虚表指针vptr。虚函数的调用关系:this->vptr->vtable->virtual function

      static全局变量和普通全局变量的区别

      • 存储方式:普通全局变量和static全局变量都是静态存储方式。
      • 作用域:普通全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,普通全局变量在各个源文件中都是有效的;静态全局变量则限制了其作用域,即只在定义该变量的源文件内有效,在同一源程序的其他源文件中不能使用它。由于静态全局变量的作用域限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其他源文件中引起错误。
      • 初始化:静态全局变量只初始化一次,防止在其他文件中使用。

      const作用及用法

      • const修饰成员变量,定义成const常量,相比于宏常量,可进行类型检查,节省内存空间,提高了效率。
      • const修饰函数参数,使得传递过来的函数参数的值不能改变。
      • const修饰成员函数,使得成员函数不能修改任何类型的成员变量(mutable修饰的变量除外),也不能调用非const成员函数,因为非const成员函数可能会修改成员变量。

      在类中的用法:

      const成员变量

      • const变量只能在类内声明,定义,在构造函数初始化列表中初始化。
      • const成员变量只在某个对象的生命周期内是常量,对于整个类而言却是可变的,不同类的const成员变量的值是不同的,因此不能在类的声明中初始化const成员变量,类的对象还没有创建,编译器不知道它的值。
      class Date{
      private:
      	const int year;
      	const int month;
      	const int day;
      public:
      	Date(int y, int m, int d) : year(y), month(m), day(d){}
      

      const成员函数

      • 不能修改成员变量的值,除非有mutable修饰;只能访问成员变量。
      • 不能调用非常量成员函数,以防修改成员变量的值。
      #include <iostream>
      using namespace std;
      class A{
      public:
      	int var;
          A(int tmp) : var(tmp){}
          void c_fun(int tmp) const //const成员函数
              var = tmp;  //在const成员函数中,不能修改任何类成员变量
              fun(tmp);  //const成员函数不能调用非const成员函数,因为非const成员函数可能会修改成员变量
          void fun(int tmp)
              var = tmp;
      

      define和const的区别

      • 编译阶段:define是在编译预处理阶段进行替换,const是在编译阶段确定其值。
      • 安全性:define定义的宏常量没有数据类型,只是进行简单的替换,不会进行类型安全的检查,const定义的常量是有类型的,是要进行判断的,可以避免一些低级错误。
      • 内存占用:define定义的宏常量,在程序中使用多少次就会有多少次替换,内存中有多个备份,占用的代码段的空间,const定义的常量占用静态存储区的空间,程序运行过程中只有一份。
      • 调试:define定义的宏常量不能调试,因为在预编译阶段就已经进行替换了,const定义的常量可以进行调试。

      const的优点:

      • 有数据类型,在定义式可进行安全性检查
      • 可调试
      • 占用较少的空间

      define和typedef的区别

      • 原理:#define 作为预处理指令,在编译预处理时进行替换操作,不作正确性检查,只有在编译已被展开的源程序时才会发现可能的错误并报错。typedef是关键字,在编译时处理,有类型检查功能,用来给一个已经存在的类型一个别名。
      • 功能:typedef用来定义类型的别名,方便使用。#define不仅可以为类型取别名,还可以定义常量,变量,编译开关等。
      • 作用域:#define没有作用域的限制,只要是在之前预定义过的宏,在以后的程序中都可以使用,而typedef有自己的作用域。
      • 指针的操作:typedef和#define在处理指针时不完全一样。
      • #define不是语句,不在末尾加分号;typedef是语句,要加分号标识结束。
      #include <iostream>
      #define INTPTR1 int*;
      typedef int* INTPTR2;
      using namespace std;
      int main(){
          INTPTR1 p1, p2; //p1: int*; p2:int
          INTPTR2 p3, p4; //p3: int*; p4:int*
         	int var = 1;
          const INTPTR1 p5 = &var; //相当于const int* p5;常量指针,即不可以通过p5去修改p5指向的内容,但是p5可以指向其他内容
          const INTPTR2 p6 = &var; //相当于int* const p6;指针常量,不可使p6再指向其他内容
      	return 0;
      

      inline作用及其使用方法

      inline是一个关键字,可以用于定义内联函数。内联函数,像普通函数一样被调用,但是在调用时并不通过函数的调用机制而是直接在调用点出展开,这样可以大大减少由函数调用带来的开销,从而提高程序的运行效率。

      使用方法:

      • 类内定义成员函数默认是内联函数。

        在类内定义成员函数,可以不用再函数头部加上inline关键字,因为编译器会自动将类内定义的函数(构造函数,析构函数,普通成员函数等)声明为内联函数。

      • 类外定义成员函数,若想定义为内联函数,需要用关键字inline声明

        当在类内声明函数,在类外定义函数时,如果想将该函数定义为内联函数,则可以在类内声明时不加inline关键字,而在类外定义函数时加上inline关键字。

      • 另外,可以在声明函数和定义函数的同时加上inline;也可以只在函数声明时加上inline,而定义函数时不加inline。只要确保在调用该函数之前把inline的信息告知编译器即可。

      explicit的作用(如何避免编译器进行隐式类型转换)作用:声明类构造函数是显式调用的,而非隐式调用,可以阻止调用构造函数时进行隐式转化。只可用于修饰单参数的构造函数,因为无参构造函数和多参构造函数本身就是显式调用的。隐式转换:#include &lt;iostream&gt;#include &lt;cstring&gt;class A{public: int var; A(int tmp) { var = tmp; }};int main(){
      1.lambda表达式 Java8最值得学习的特性就是Lambda表达式和Stream API,如果有python或者javascript的语言基础,对理解Lambda表达式有很大帮助,因为Java正在将自己变的更高(Sha)级(Gua),更人性化。--------可以这么说lambda表达式其实就是实现SAM接口的语法糖。 lambda写的好可以极大的减少代码冗余,同时可读性也好过冗长的内部类,匿名类。
      C++关键字explicit的详细介绍介绍实例未加explict的类的隐式转换加explicit修饰的构造函数不能隐式类型转换总结 首先一句话记住他的使用范围:explicit关键字只用于修饰C++中只有一个参数的构造函数,这就是它的全部作用域,下面一句话说出explicit的作用:用于声明该类的构造函数(只有一个参数)是显示调用的。 因为默认情况下,类的构造函数都是implicit的,它可...
              1、天真热,程序员活着不易,星期天,也要顶着火辣辣的太阳,总结这些东西。         2、夸夸lambda吧:简化了匿名委托的使用,让你让代码更加简洁,优雅。据说它是微软自c#1.0后新增的最重要的功能之一。 lambda简介      lambda运算符:所有的lambda表达式都是用新的lambda运算符 " =&gt; ",可以叫他,“转到”或者 “成为”。...
      #include &lt;iostream&gt; #include &lt;vector&gt; #include &lt;algorithm&gt; //for_each... #include &lt;functional&gt; //plus&lt;int&gt;()... #include &lt;numeric&gt; //accumulate... //l...
      C++提供了关键字explicit,可以阻止不应该允许的经过转换构造函数进行的隐式转换的发生,声明为explicit的构造函数不能在隐式转换中使用。 C++中, 一个参数的构造函数(或者除了第一个参数外其余参数都有默认值的多参构造函数), 承担了两个角色。  1 是个构造;2 是个默认且隐含的类型转换操作符。 所以, 有时候在我们写下如 AAA = XXX, 这样的代码, 且恰好XXX的类型
      1. 介绍 在C++11标准中,引入了lambda表达式,通过lambda表达式在代码中的使用,可以大大简化C++的代码,使得代码更加清晰并且容易阅读。 lambda表达式在概念上,个人理解为是一个匿名的内部函数,然后通过函数指针的方式使外部可以使用这个内部函数。 lambda表达式的结构如下所示: [捕获列表] (参数列表)-> 返回类型 { 函数体 } int classicLambda() int a = 10; auto cLambda = [&a](in
      在Android中,分析内存不足的关键字通常包括: 1. OutOfMemoryError:这是Java虚拟机抛出的一种错误,表示应用程序尝试使用超出其可用内存限制的内存。通常会在应用程序崩溃时出现。 2. GC(Garbage Collection):垃圾回收是一种自动内存管理技术,可以自动识别并删除不再需要的对象。在Android日志中,您可能会看到GC的各种消息,例如“GC_CONCURRENT”、“GC_FOR_ALLOC”、“GC_EXPLICIT”等,这些消息提供了有关系统如何回收内存的信息。 3. LowMemory:这是一个系统事件,表示设备的可用内存已经非常有限。当操作系统检测到设备内存不足时,它会发送这个事件,以便应用程序可以采取必要的措施来释放内存。 4. DalvikVM:Dalvik是Android操作系统的运行时环境。在Android日志中,您可能会看到各种DalvikVM消息,例如“GC_FOR_ALLOC”、“GC_CONCURRENT”、“WAIT_FOR_CONCURRENT_GC”等,这些消息提供了有关系统如何管理内存的信息。 5. MemoryLeak:内存泄漏是指应用程序在使用对象时未能正确释放内存的情况。内存泄漏可能导致应用程序消耗过多的内存,最终导致应用程序崩溃或系统变得不稳定。在Android日志中,您可能会看到“MemoryLeak”或“LeakCanary”等关键字,这些消息提供了有关内存泄漏的信息。
 
推荐文章
失落的汽水  ·  Building a Real-Time Chat Micro-Frontend with Vue 3, Vite, and Module Federation
1 月前
讲道义的脸盆  ·  解析或序列化 XML - XML:可扩展标记语言 | MDN
3 周前
跑龙套的单杠  ·  分享6个对象数组去重的方法开发者社区
3 周前
纯真的炒饭  ·  MongoDB数据库中更新与删除数据 - 龙恩0707
2 周前
体贴的红金鱼  ·  在 Office 加载项中使用 Office 对话框 API - Office Add-ins | Microsoft Learn
2 周前
英姿勃勃的松鼠  ·  Date() 构造函数 - JavaScript | MDN
1 年前
淡定的斑马  ·  “耗尽”人类语言:ChatGPT还有多少数据可用?-虎嗅网
2 年前
高大的凉茶  ·  onlyoffice+vue集成_onlyoffice vue_阿阿G讷的博客-CSDN博客
2 年前
痴情的键盘  ·  ”System.InvalidOperationException”类型的未经处理的异常出现在 mscorlib.dll 中_土豆赛叩的博客-CSDN博客
2 年前
踢足球的围巾  ·  archlinux下,dwm/i3下截图解决方案_i3 和dwm_zhen12321的博客-CSDN博客
2 年前
今天看啥   ·   Py中国   ·   codingpro   ·   小百科   ·   link之家   ·   卧龙AI搜索
删除内容请联系邮箱 2879853325@qq.com
Code - 代码工具平台
© 2024 ~ 沪ICP备11025650号