【CPP】CPP的语法糖&引用&内联函数&nullptr

这里是oldking呐呐,感谢阅读口牙!先赞后看,养成习惯!

个人主页:oldking呐呐
专栏主页:深入CPP语法口牙


5 语法糖

  • 语法糖指在编程语言原有语法的基础上扩展的语法形式,语法糖的使用会让代码更加简洁,可读性更高
  • 例如:中文中的"什么"和"啥"这样的关系,"什么"是"官方正经"的语法形式,而"啥"则就是语法糖,听着稍微偏门一些但确实更加简洁了

6 引用 – reference

  • 引用是一种CPP中的语法糖,一般我们用它解决传址调用出现的频繁解引用的问题,它可以代替一部分指针的作用
6.1 引用在非函数定义中的使用
  • 引用可以当作一个变量使用,但定义的引用在内存中并不存在,你可以理解为变量的一个别称,类似于typedef,只不过typedef是给类型取别名,而引用是给变量取别名
int a = 10;
int& ref = a;

ref = 1;    //此时a就被改成了1了
  • 在以上代码,ref即a的引用,值得注意的是,这里ref的类型应该是int&,&int应该是一体的
  • 编译过后ref会被替换成a,原本的refref的定义会直接消失
  • 引用必须初始化,引用不初始化会报错

  • 如果你想中途更改ref引用的目标变量,那请你把ref改成指针,因为引用ref压根就不能改,指针才能改

int a = 10;
int b = 20;

int& ref = a;

ref = b;    //这样做相当于把b的值赋值给a,ref依旧引用a 
6.2 引用在函数定义中的使用
  • 引用在函数定义中用于替代一部分指针的作用,用于避免频繁解引用指针变量,使代码更加简洁美观,在函数定义中的引用只可以在函数内部使用
void add(int* ret, int* x, int* y)
{
    *ret = *x + *y;
}
  • 在使用了引用之后的效果
int main()
{
    int x = 1;
    int y = 2;
    int ret = 0;

    add(ret, x, y);  //这里不需要传地址进去

    return 0;
}
void add(int& ret, int& x, int& y)
{
    ret = x + y;    //这里的效果和传址调用是一样的
}
  • 在这里引用一样可以改变原来变量的空间中的值

  • 函数返回值中也可以添加引用,在类与对象终会非常有用,简单来说正常情况下返回值相当于是个常量,只能赋值/传参给别的变量/函数,但如果返回的是某个作用域不仅在本函数内的变量的引用,那这个返回值就可以被赋值,对返回值赋值!(如果作用域在本函数内,函数调用完之后该变量就会被销毁,此时返回引用的操作就会导致报错之类的)

  • 比较复杂的情况我们以后再说

6.3 引用与const
  • 我们来看看下面这个例子
    请添加图片描述

  • 这里是一个经典的权限放大的问题

  • 原本a的权限为只读而非读写,现在你给a整一个引用,那是不是就可以通过这个引用来修改原来a的值了???

  • 这里其实就是把a只读的权限放大为读写了,直接就会报错

  • 不把权限放大的写法

int main()
{
	const int a = 0;
	const int& ra = a;

	return 0;
}
  • 也就是说,对于const对象只能用const引用,即权限平移

  • 当然,权限缩小也是可以的

int main()
{
	int b = 0;
	const int& rb = b;

	return 0;
}
  • 当然权限缩小仅限于rb,b的权限依旧没变的,想咋改咋改

  • 当然你甚至可以给一个数字取别名

	const int& rc = 30;
  • 甚至你可以给表达式取别名,临时对象具有常性,(a + b)在运算过后会生成一个临时变量
	int a = 1;
	int b = 2; 
	const int& rc = (a + b);
  • 同样的,因为临时变量具有常性,所以在发生类型转换产生的临时变量也可以取别名
	double a = 3.14;
	const int& ra = a;
  • 此时ra3的别名而不是a的别名
6.4 引用与指针
  • 引用只包含指针的部分功能,很多地方引用不能用还是需要指针
    • 语法上引用是某个对象的别名,不开空间,而指针是开空间的
    • 引用定义后必须初始化,指针建议初始化,但不强制
    • 引用指定一个对象之后就不能再更改,而指针可以
    • 引用可以直接访问被指向的对象,指针需要解引用才行
    • sizeof下,引用是实际对象的大小,指针则是4/8字节
    • 指针容易出现野指针的问题,引用几乎不可能会出现这样的问题

7 inline修饰 – 内联函数

  • inline修饰的函数被称为内联函数,调用内联函数的时候会直接将函数在当前栈帧展开,意味着内联函数的栈帧就不建立了,直接展开直接用,不建立栈帧就可以提高效率
  • inline修饰函数对于编译器来讲只是一个建议而已,编译器也完全可以不按照内联函数展开,而是按照正常函数创建栈帧,因为CPP压根就没有规定过这个,能不能用完全取决于编译器,内联函数适用于比较短小然后又要经常用的函数,对于递归来讲就不太适合了,很多编译器你在递归函数前修饰inline也会被编译器忽略

一般情况下,五到十条语句就差不多了,再往上走编译器就会选择性忽略inline了,inline和宏函数还是很像的,但区别在于宏函数是在预处理的时候对高级语言代码做手脚(替换),而inline是在编译的时候对汇编代码做手脚(几乎也算是替换),避免产生函数栈帧,速度的确快,但如果频繁展开一个很长的函数,那完全展开之后的汇编代码就非常非常长,导致生成的可执行文件变得很大,所以说对于很多行代码的内联函数,编译器会忽略,而忽略之后就没必要展开,只需要建立栈帧一次就行,可执行文件就不会变得那么大,inline其实本质上就是用空间换时间罢了,编译器自己会考虑一下性价比,再来看该不该用内联函数

  • C在实现宏函数的时候会在预处理时展开,但宏函数实现非常复杂而且很容易出问题,而且不方便调试,CPP设计的内联函数就是为了替代宏函数而产生的
#define ADD(a, b) ((a)+(b))

inline int Add(int a, int b)
{
	return (a + b);
}

int main()
{
	cout << ADD(1, 2) << endl;
	cout << Add(1, 2) << endl;
	return 0;
}

以上这个例子的宏函数就必须要保证运算符优先级正确,保证替换后不成语句,就必须要加一堆括号,而且不能加;,写起来很复杂,而内联函数就是一个正儿八经的函数,按函数那套逻辑写就行了,既完成了减少函数开辟栈帧使效率提升的目的,还大大降低了错误发生的概率

  • vs下被inline修饰的函数默认不会在debug下展开,如果要在debug下展开的话需要设置
  • inline不建议定义和声明分离到两个文件,这样链接的时候会出错,因为inline一旦被展开就没有函数地址,链接就会出错,所以一般情况下内联函数我们直接放进.h里头

8 nullptr(C++11)

  • 原来我们在C中一直都用的NULL,这玩意就是个宏定义,在C下是(void*)0即0被强转为了(void*),而CPP下则就被宏定义为0,但这玩意在CPP下有着巨大的坑,我们看例子
void func(int x)
{
	cout << "int x" << endl;
}

void func(int* px)
{
	cout << "int* px" << endl;
}

int main()
{
	func(0);
	func(NULL);

	return 0;
}

请添加图片描述

请添加图片描述

CPP对于指针检查会更加严格一些,CPP不允许(void*)赋值给其他类型的指针,而C语言中就可以,所以哪怕在使用的时候强转成(void*)也不一定会编译通过
请添加图片描述

  • 因为CPP下指针使用的检查更加严格,我们发现CPP下的NULL和我们在C下的NULL使用习惯不符,所以在CPP下我们新定义了一个nullptr的玩意,专门用来代表空指针

  • nullptr是一个CPP的一个关键字,它可以且只可以被隐式转换成其他任意类型的指针,但不能被转换成任何整数类型

void func(int x)
{
	cout << "int x" << endl;
}

void func(int* px)
{
	cout << "int* px" << endl;
}

int main()
{
	func(0);
	func(nullptr);

	return 0;
}

请添加图片描述

  • 所以我们在CPP下更推荐用nullptr而不是NULL
### C++ 基础语法概述 C++ 是一种功能强大且灵活的编程语言,其基础语法涵盖了变量声明、输入输出操作、控制结构以及函数定义等内容。以下是关于 C++ 基础语法的一些核心知识点: #### 变量与数据类型 在 C++ 中,可以使用多种基本数据类型来存储不同种类的数据。常见的数据类型包括 `int`(整数)、`float` 和 `double`(浮点数)、`char`(字符)等[^1]。 ```cpp #include &lt;iostream&gt; using namespace std; int main() { int integerVariable = 10; float floatingPointVariable = 3.14f; char characterVariable = &#39;A&#39;; cout &lt;&lt; &quot;Integer: &quot; &lt;&lt; integerVariable &lt;&lt; endl; cout &lt;&lt; &quot;Float: &quot; &lt;&lt; floatingPointVariable &lt;&lt; endl; cout &lt;&lt; &quot;Char: &quot; &lt;&lt; characterVariable &lt;&lt; endl; return 0; } ``` #### 输入与输出 C++ 提供了标准库 `&lt;iostream&gt;` 来处理输入和输出操作。通过 `cin` 对象可以从标准输入读取数据,而 `cout` 则用于向标准输出写入数据。 ```cpp #include &lt;iostream&gt; using namespace std; int main() { int number; cout &lt;&lt; &quot;请输入一个整数:&quot;; cin &gt;&gt; number; cout &lt;&lt; &quot;您输入的是:&quot; &lt;&lt; number &lt;&lt; endl; return 0; } ``` #### 控制流语句 C++ 支持各种控制流语句,如条件判断 (`if`, `else`) 和循环 (`for`, `while`, `do-while`) 等。这些语句允许开发者编写复杂的逻辑流程。 ```cpp #include &lt;iostream&gt; using namespace std; int main() { int count = 5; while (count &gt;= 0) { cout &lt;&lt; &quot;计数器值为:&quot; &lt;&lt; count-- &lt;&lt; endl; } return 0; } ``` #### 函数定义 函数是一段可重复使用的代码块,能够执行特定的任务。可以通过关键字 `return` 返回计算结果给调用者。如果不需要返回任何值,则应指定返回类型为 `void`。 ```cpp #include &lt;iostream&gt; using namespace std; // 定义加法函数 int add(int a, int b) { return a + b; } int main() { int result = add(3, 7); cout &lt;&lt; &quot;相加的结果是:&quot; &lt;&lt; result &lt;&lt; endl; return 0; } ``` #### 外部链接符 extern &quot;C&quot; 当需要在一个 C++ 库中兼容 C 风格接口时,通常会采用 `extern &quot;C&quot;` 关键字包裹头文件或者函数声明部分。这样做是为了防止 C++ 编译器对符号名进行修饰从而破坏与其他语言之间的互操作性[^2]。 ```cpp #ifdef __cplusplus extern &quot;C&quot; { #endif void c_style_function(); #ifdef __cplusplus } #endif ``` #### 数组与指针 数组是一种连续内存区域中的相同类型的元素集合;指针则保存着某个对象或变量所在位置的信息。下面展示了如何获取二维数组第一个元素地址的方法[^3]。 ```cpp #include &lt;iostream&gt; using namespace std; int main(){ int arr[2][2]; cout &lt;&lt; &quot;首元素地址:&quot; &lt;&lt; (int)&amp;arr[0][0] &lt;&lt; endl; return 0; } ```
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值