【C++】入门与过渡

发布时间:2024年01月12日

【C++】入门与过渡


注:本文为学习笔记,只记录了一些重点,有些比较简单的内容做了省略

一、命名空间

解决问题:对标识符的名称进行本地化,以避免命名冲突或名字污染

使用方法:

  • 命名空间名称及作用域限定符::,前面没有命名空间表示全局
  • 使用using将命名空间中成员引入
  • 使用using namespace 命名空间名称引入

注意:

  • 命名空间可以嵌套
  • 同名的命名空间将被合并
  • 命名空间影响的是编译查找规则。使用命名空间后,查找范围为:局部、全局、命名空间
  • 一般练习用哦namespace,实际项目最好不用

示例:

std::cout << "hello world";
using std::cout;
using namespace std;

二、输入输出(cin/cout)

使用:

#include <iostream>

int main() {
	std::cout << "input: ";
	int a = 0;
	std::cin >> a;
	std::cout << "output: " << a << std::endl;
	return 0;
}

注意:取消缓冲区同步语句 std::ios::sync_with_stdio(false)

三、缺省参数

作用:缺省参数是声明或定义函数时为函数的参数指定一个默认值

分类:

  • 全缺省参数void test(int a = 1, int b = 2, int c = 3)
  • 部分缺省参数void test(int a, int b = 1, int c = 2)

注意:

  • 半缺省参数必须从右往左依次来给出,不能出现间隔
  • 缺省参数不能在函数声明和定义中同时出现。若声明和定义进行分离,需要使用缺省参数,必须在声明中给出。
  • 缺省值必须是常量或者全局变量

四、函数重载

作用:C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数、类型、顺序)不同

使用

int Add(int left, int right);
int Add(int left, int right,int temp);

int Add(int left, int right);
double Add(double left, double right);

double Add(double left, int right);
double Add(int left, double right);

注意:

  • 类型将自动识别
  • 会影响编译速度,但不会影响运行速度
  • 同一作用域
  • double与float的传参区分需要注意后缀有没有f
  • 可以从函数名修饰的规则来理解重载,返回值不同不能构成重载

原理补充:

  • c++函数名修饰规则,从而区别不同函数,不同平台修饰规则是不同的。
  • c++将会用修饰以后函数名去寻找函数的地址

五、引用

作用

给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间

使用

  • 定义,相当于给已存在变量取了一个别名,用不同的变量名来标识同一块地址空间;

    int a = 0;
    int& b = a;
    
  • 输出型参数,此时形参的改变会影响实参;

    void swap(int* p1, int* p2);
    void swap(int& r1, int& r2);
    
  • 传引用返回,出了作用域返回的变量还在。调用函数栈帧的销毁,不影响返回值的生命周期;

    如果函数返回时,出了函数作用域,如果返回对象还未还给系统,则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。多用于:静态变量、全局变量、上一层栈帧、堆区等。

    // 引用返回 1、减少拷贝 2、调用者可以修改返回对象
    int& PosAt(AY& ay, int i){
    	return ay.a[i];
    }
    int main(){
    	int ret = Count();
    	AY ay;
    	for (int i = 0; i < N; ++i){
    		PosAt(ay, i) = i*10;
    	}
    	for (int i = 0; i < N; ++i){
    		cout << PosAt(ay, i) << " ";
    	}
    	cout << endl;
    	return 0;
    }
    

  • 区分引用和取地址,类型+&为引用,&+变量为取地址

  • 引用定义时必须初始化

  • 一个变量可以存在多个引用

  • 引用一旦引用一个实体,不能再引用其他实体

  • 值和引用的作为返回值类型的性能比较下,引用的作为返回值性能可能更优秀。

  • 常引用:赋值/初始化时,权限可以不变或者缩小,但是不能放大(指针同理)

    临时变量具有常性,函数返回为临时变量、类型转换(中间会产生临时变量),也只能用常引用

    const int a = 2;
    //int& b = a; 错误
    const int& b = a; //正确
    

指针和引用的区别

  • 语法概念:引用没有开空间,指针开辟了空间并存入了地址。引用在语法的层面上是变简单了
  • 底层实现:也是开辟了一个空间,将有效地址写入。从汇编上看引用也是用指针实现的
  • 引用必须初始化,指针没有要求
  • 引用一个实体后,不能再引用其他实体,指针没有要求
  • 没有NULL的引用,但有空指针
  • sizeof的含义不同
  • 自增自减的意义不一样
  • 有多级指针,但是没有多级引用
  • 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
  • 引用比指针使用起来相对更安全

六、内联函数

定义:以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销,内联函数提升程序运行的效率。

使用

inline void test(int i){
	cout << i << endl;
}

注意

  • 替换宏函数:宏的缺点是纯粹简单的替换,无法调试,没有安全的类型检查并且在有些场景中非常的复杂
  • 因此cpp推荐使用const和enum替换宏常量,inline替代宏函数
  • 在使用inline后,就不会建立函数栈帧(需要在release模式下才能观察到)
  • 是一种以空间换时间的做法,省去调用函数额开销,但是如果存在循环将可能造成空间浪费,因为会在每处调用处进行指令展开
  • 编译器会自动优化,如果定义为inline的函数体内有循环/递归等等,编译器优化时会忽略掉内联
  • inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到(可以直接在.h文件里面直接定义)
  • 可以在同一个项目的不同源文件内定义函数名相同但实现不同的inline函数,因为inline函数会在调用的地方展开,所以符号表中不会有inline函数的符号名,不存在链接冲突。

七、auto关键字

作用:

  • 编译器自动推导变量类型,作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得
  • 当类型很长时,可以简化代码

使用

  • 自动判断类型

    int a = 10;
    auto b = a;
    
  • 范围for 意义和使用:自动依次取数组中数据赋值给e对象,自动判断结束

    注意:for循环迭代的范围必须是确定的;迭代的对象要实现++和==的操作

    void test(){
        int array[] = { 1, 2, 3, 4, 5 };
        for(auto& e : array) 
            e = 1;
        for(auto e : array)
            cout << e << " ";
        return 0;
    }
    

注意

  • 缺点:无法显示获取变量的类型
  • auto e; 无法通过编译,使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编译期会将auto替换为变量实际的类型
  • auto*auto&,分别限定了必须为指针和引用
  • 同一行定义多个变量:当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量
  • 不能使用的场景:不能作为函数的参数,不能用于声明数组

八、空指针

NULL与nullptr的区别:

  • NULL可能被定义为字面常量0,或者被定义为无类型指针(void*)的常量

    #ifndef NULL
    #ifdef __cplusplus
    #define NULL 0
    #else
    #define NULL ((void *)0)
    #endif
    #endif
    
  • 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入的

  • 在C++11中,sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同

文章来源:https://blog.csdn.net/qq_66725576/article/details/135560420
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。