首页 > 编程语言 >C++基础知识概述(二)

C++基础知识概述(二)

时间:2024-11-20 23:18:40浏览次数:1  
标签:const int 30 C++ 基础知识 概述 引用 20 指针

一、形参带默认值的函数

 

二、inline内联函数

三、const用法

1.const修饰的变量不能作为左值,初始化完成后,值不能修改 

2.C与C++中const的区别是:编译方式不同 

C:作为一个变量来编译生成指令,C中的const可以不必被初始化,能正常编译,不叫常量,叫常变量。

    const int a = 20;
    int array[a] = {};//不可以用作数组的索引,编译会报错,因为是个变量,在运行的时候才会复赋值
    int* p = (int*)&a;
    *p = 30;
    printf("%d,%d,%d\n", a, *p, *(&a));

    //输出结果:30 30 30

 

C++:所有const常量名字的地方,都被常量的初始化替换了,C++的const必须被初始化,不初始化会报错,可以说是个常量。

    const int a = 20;
    int array[a] = {};//可以用作数组的索引,因为是个常量
    int* p = (int*)&a;
    *p = 30;
    //20 30 20
    printf("%d,%d,%d\n", a, *p, *(&a));

    //输出结果:20 30 20

这个时候a的内存已经改成了30,而C++在编译的时候已经把a替换成20这个字面量了,所以其实可以说是常量

如果用一个变量来初始化,那么因为初始值不是一个立即数,所以此时的a是个常变量,可以说是个变量

    int b = 20;
    const int a = b;
    int array[a] = {};//不可以用作数组的索引,编译会报错,因为是个变量,在运行的时候才会复赋值
    int* p = (int*)&a;
    *p = 30;
  
    printf("%d,%d,%d\n", a, *p, *(&a));

    //输出结果:30 30 30

  

四、函数重载

五、左值引用与右值引用

1.引用是一种更安全的指针,引用必须初始化,但指针可以不初始化。

    int a = 10;
00007FF7A6A0236E  mov         dword ptr [a],0Ah  
    int* p = &a;
00007FF7A6A02375  lea         rax,[a]  
00007FF7A6A02379  mov         qword ptr [p],rax  
    int& b = a;
00007FF7A6A0237D  lea         rax,[a]  
00007FF7A6A02381  mov         qword ptr [b],rax  

    *p = 20;
00007FF7A6A02385  mov         rax,qword ptr [p]  
00007FF7A6A02389  mov         dword ptr [rax],14h  

根据汇编代码可以看出,引用和指针都是通过操作地址来进行的,所以定义引用变量时需要初始化并且用于初始化的这个值一定要能取地址,所以int & c=20;这个表达式是错的

2.引用只有一级引用,没有多级引用,指针可以有一级指针,也可以有多级指针

3。定义一个引用变量和定义一个指针变量,其汇编指令是一模一样的;通过引用变量修改所引用内存的值,和通过指针解引用修改指针指向的内存的值,其底层指令也是一模一样的 。

左值与右值:

左值:有内存,有名字,值可以修改                右值:没内存,没名字,直接放入寄存器

    int a = 10;
00007FF75D551EFE  mov         dword ptr [a],0Ah  
    int& b = a;
00007FF75D551F05  lea         rax,[a]  
00007FF75D551F09  mov         qword ptr [b],rax  

    //int& c =20;
    //C++提供了右值引用
    int&& C = 20;
00007FF75D551F0D  mov         dword ptr [rbp+64h],14h  
00007FF75D551F14  lea         rax,[rbp+64h]  
00007FF75D551F18  mov         qword ptr [C],rax  
    C = 30;
00007FF75D551F1C  mov         rax,qword ptr [C]  
00007FF75D551F20  mov         dword ptr [rax],1Eh  

    /*
     int temp =20;
     temp -> b
    */
    const int& d = 20;
00007FF75D551F26  mov         dword ptr [rbp+0A4h],14h  
00007FF75D551F30  lea         rax,[rbp+0A4h]  
00007FF75D551F37  mov         qword ptr [d],rax  
    //d=30;

从反汇编可以看到,右值引用专门用来引用右值类型,指令上,可以自动产生临时量,然后直接引用零适量,右值引用与const int&基本相同,但不同的是右值引用变量可以直接修改,但const int&不行

int &e=C;是可以的,一个右值引用变量,本身就是一个左值,但是int &&e=c;是不可以的,一个右值引用必须引用一个右值,不能是一个左值,因为右值引用引用的是右值,而右值是直接输入到寄存器里面的,必须生成一个临时量

 

六、const与一、二级指针结合

1.const 修饰的量常出现的错误是:

1)常量不能再作为左值,即直接修改常量的值

2)不能把常量的地址泄露给一个普通的指针或者普通的引用变量,即间接修改常量的值

 

2. const 与一级指针的结合

C++的语言规范:const修饰的是离他最近的类型。    int a = 20;

const int* p = &a;//==>*p=20 错误  p=&b  正确
    //此时int本身就是一个类型,所以const 修饰的是int,所以const修饰的表达式是*p,所以不能通过指针间接修改指向的内存的值 ,但是p这个指针本身没有被const修饰,所以可以赋予其不同int 类型的内存地址
  

    int a = 20;
    int* const p=&a;//==> p=&b 错误 *p=20 正确
    //此时这个指针p是常量,不能再指向其他内存,但是*p不是,所以可以通过指针解引用的方式修改指向内存里的值

总结const与指针的类型转换公式:

int*  <==  const int*  是错误的     const int* <==  int* 是可以的 

int** <== const int**  是错误的!          const int** <==int**   是错误的   

const与二级指针的结合两边必须都有const,不能一边有const,一边没有const

int**  <==  int* const*   是错误的           int* const*  <== int**  是可以的

以上两个其实不是二级指针的转换而是一级指针的转换,其实只考虑const后面的*即可,故可以转换为:

int*  <==  const int*  是错误的     const int* <==  int* 是可以的 这两种来比较

int* q1 = nullptr;
int* const q2 = nullptr;
std::cout << typeid(q1).name() << std::endl;
std::cout << typeid(q2).name() << std::endl;
//输出结果: int*         int*
//const如果右边没有指针*的话,const 是不参与类型的

int a = 10;
int* p1 = &a;
const int* p2 = &a; //const int* <== int* 
int* const p3 = &a; // int* <== int*
int* p4 = p3; //int* <== int*

 

3.  const 与二级指针的结合

    int a = 10;
    int* p = &a;
    int** q = &p;

此时的二级指针q有三种情况:q     *q      **q

const int **q ;  此时离const最近的类型是int ,故**q不能被赋值,即a的值不能被改变,但p和q的值可以被改变

int *const*q; 此时离const最近的类型是int*,故*q不能被赋值,即p的值不能被改变,但q和a的值可以被改变

 int **const q; 此时离const最近的类型是int**,故q不能被赋值,即q的值不能被改变,但p和a的值可以被改变

至于const int **q=&p;则是错误的,因为该表达式如果成立则有可能导致把一个常量的地址泄露给普通的指针,此时可以说*q就是p,而*q此时被const修饰,所以是常量的地址泄露给了p,p可以修改,故不成立。

 

七、const、指针、引用的结合使用

不能判断的时候可以将引用&转换成指针来理解:即左边把引用&换成指针*,右边取地址加上&

标签:const,int,30,C++,基础知识,概述,引用,20,指针
From: https://www.cnblogs.com/treelakes/p/18526202

相关文章

  • 深入理解C++11右值引用与移动语义:高效编程的基石
    文章目录前言......
  • C++ list (链表)容器
    C++ list 链表#include<iostream>usingnamespacestd;#include<list>voidprintList(constlist<int>&L){ for(list<int>::const_iteratorit=L.begin();it!=L.end();it++) { cout<<*it<<"";......
  • C++ 模板元编程高级技巧与大型项目架构中的应用实践
    C++模板元编程(TemplateMetaprogramming,TMP)是一种利用C++模板在编译时进行计算和逻辑推理的技术。模板元编程可以极大地提升程序的灵活性、性能和可扩展性,尤其是在大型项目的架构中,能够有效地处理类型推导、优化计算和代码生成等任务。随着C++11、C++14、C++17和C++20......
  • C++零基础入门:趣味学信息学奥赛从“Hello World”开始
    编程学习的第一步,往往从“HelloWorld”开始。这不仅是程序员的“入门仪式”,更是打开编程世界的一把钥匙。结合树莓派Pico开发板的实际操作,这篇文章将为C++零基础的学生和信息学奥赛爱好者讲解如何通过一个简单的“HelloWorld”项目,学会基础语法、编程思维,以及软硬件结合的实......
  • c++引用传参是否能完全避免临时对象?
    我们都知道引用和指针传递是为了避免传参产生临时对象 今天我在温习模板特化的时候发现引用传参也可能会产生临时对象所以我较了下面函数传参6种情况A&  constA&  A*  constA*  A*&  constA*& 这些情况是否会有临时对象1.const type*&#include<......
  • 【c++丨STL】stack和queue的使用及模拟实现
    ......
  • C++ 基类构造函数内调用虚函数会怎样
    classCatBase{public:CatBase(){show1();}~CatBase(){}//virtualvoidshow1()=0;//如果不实现,运行时会错误virtualvoidshow1(){cout<<"catbase..."<<'\n';}};......
  • SQL语法基础知识总结
    目录基本概念数据库术语SQL语法SQL语法结构SQL语法要点SQL分类数据定义语言(DDL)数据操纵语言(DML)事务控制语言(TCL)数据控制语言(DCL)增删改查插入数据更新数据删除数据查询数据基本概念数据库术语数据库(database)-保存有组织的数据的容器(通常是一个文件或......
  • 检验 C++ 入门能力:试试亲手实现日期类吧!
    ......
  • C++中的初始化列表
    初始化参数列表用于在构造函数中初始化类的数据成员。语法:构造函数():属性1(值1),属性2(值2)......{}性质:1.只能在构造函数中使用2.引用或常量必须在初始化参数列表中初始化3.初始化的顺序和成员变量的顺序一致,与初始化参数列表中的顺序无关#include<iostream>#include<vect......