00-c++常用语法

函数重载

规则

  • 函数名相同
  • 参数个数不同、参数类型不同、参数顺序不同

注意

  • 函数返回值类型与函数重载无关
  • 调用函数时,实参的隐式类型转换可能会产生二义性

函数重载的本质:采用了name mangling技术,会对函数名进行改变修饰,生成多个不同的函数名,不同的编译器规则不一样。
例如win平台下:(设置属性中C++优化一项,禁用release优化)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KUKlRwFB-1619342327420)(media/16189751668924/16190076999745.jpg)]
mac平台下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MXGlGGSx-1619342327423)(media/16189751668924/16190078310876.jpg)]

static 和 extern区别

static:在定义函数时,在函数的最左边加上static可以把该函数声明为内部函数(又叫静态函数),这样该函数就只能在其定义所在的文件中使用。如果在不同的文件中有同名的内部函数,则互不干扰。可以用来声明内部函数。
extern:在定义函数时,如果在函数的最左边加上关键字extern,则表示此函数是外部函数,可供其他文件调用。C语言规定,如果在定义函数时省略extern,则隐含为外部函数。在一个文件中要调用其他文件中的外部函数,则需要在当前文件中用extern声明该外部函数,然后就可以使用,这里的extern也可以省略。

#pragram once

  • #ifndef #define #endif 受C\C++标准的支持,不受编译器的任何限制,可以修饰一个文件中的部分代码
  • 有些编译器不支持#pragma once(较老编译器不支持,如GCC 3.4版本之前),兼容性不够好,而且只能够修饰整个文件的内容

extern “C”

  • extern "C"修饰的代码会按照C语言的方式去编译。
  • 如果函数同时有声明和实现,要让函数声明被extern "C"修饰,函数实现可以不修饰
  • C++在调用C语言API时,需要使用extern "C"修饰C语言的函数声明,为了适用性,一般会添加宏定义
    #ifdef __cpluscplus
        extern "C" {
    #endif // __cpluscplus

    #ifdef __cpluscplus
        }
    #endif // __cpluscplus

内联函数(代码体积不大,频繁调用)

  • 使用inline修饰函数的声明或者实现,可以使其变成内联函数。建议声明和实现都添加上inline
  • 编译器会将函数调用直接展开为函数体代码,减少函数的调用开销,但是增加代码体积
  • 内联函数不建议过长(例如超过10行),有些函数即使添加inline也不是内联函数,比如递归函数
int sum(int a, int b) {
	return a + b;
}
正常的函数调用开辟函数栈空间,将参数压栈后调用函数进行执行
#sum(10, 20)

009710C8 6A 14                push        14h  
009710CA 6A 0A                push        0Ah  
009710CC E8 AF FF FF FF       call        sum (0971080h)  
009710D1 83 C4 08             add         esp,8  
009710D4 50                   push        eax  

修改sum为内联函数的话,可以观察到编译器直接进行了函数的替换
00151004 B8 0A 00 00 00       mov         eax,0Ah  
00151009 83 C0 14             add         eax,14h  
0015100C 89 45 FC             mov         dword ptr [c],eax 

如果设置成内联函数的话,那么生成的可执行文件中不会存在相应的函数。

内联函数与宏

  • 内联函数和宏,都可以减少函数调用的开销
  • 对比宏,内联函数多了语法检测和函数特性

C++表达式赋值

int a = 1;
int b = 2;
(a = b) = 3; // 等效于a = 3
(a < b ? a : b) = 4; //等效于b = 4

const常量

//    const只修饰它右边的,看的就是*p 或者 p 与类型无关
int age = 10;
int height = 10;

//    *p1是常量 p1不是
const int * p1 = &age;
//    *p2是常量 p2不是
int const * p2 = &age;
//    p3是常量 *p3不是
int * const p3 = &age;
//    p4是常量 *p4也是
const int  * const p4 = &age;
//    p5是常量 *p5也是
int const * const p5 = &age;

引用

注意

  • 引用相当于是变量的别名(基本数据类型、枚举、结构体、类、指针、数组等,都可以有引用) (只观察&符号左边的是什么类型即可)
  • 对引用做计算,就是对引用所指向的变量做计算
  • 在定义的时候就必须初始化,一旦指向了某个变量,就不可以再改变,“从一而终”
  • 可以利用引用初始化另一个引用,相当于某个变量的多个别名
  • 不存在【引用的引用、指向引用的指针、引用数组】

引用的本质就是指针,只是编译器削弱了它的功能,所以引用就是弱化了的指针
机器码证明 引用就是指针
观察机器码都是一样子的

47: 	int *p = &age;
89 45 F4             mov         dword ptr [p],eax  
	48: 	*p = 20;
8B 4D F4             mov         ecx,dword ptr [p]  
C7 01 14 00 00 00    mov         dword ptr [ecx],14h 

50: 	int &ref = age;
89 45 F4             mov         dword ptr [ref],eax  
	51: 	ref = 20;
8B 4D F4             mov         ecx,dword ptr [ref]  
C7 01 14 00 00 00    mov         dword ptr [ecx],14h 

常引用
引用可以被const修饰,这样就无法通过引用修改数据了,可以称为常引用
const必须写在&符号的左边,才能算是常引用

//*p不能修改内容 但是p可以修改指向
int const *p = &age;
*p = 20; //error
p = &height;

//p1不能修改指向 但是能利用*p1间接修改指向的变量
int * const p1 = &age;
*p1 = 10;
p1 = &height; //error

//ref不能修改指向 也不能利用ref间接修改指向的变量
int const &ref = age;
ref = 20; //error

//ref1不能修改指向 但是能利用ref1间接修改指向的变量
int & const ref1 = age;
ref1 = 20;

const引用的特点

  • 可以指向临时数据(常量、表达式、函数返回值等)
int const &ref = 30;

int a = 1;
int b = 2;
int const &ref1 = a + b;

int func1() {
	return 8;
}
int const &ref2 = func1();
  • 可以指向不同类型的数据
double const &ref3 = 30;
  • 作为函数参数时(此规则也适用于const指针)
    • 可以接受const和非const实参(非const引用,只能接受非const实参)
int test1(int &v1, int &v2) {
return v1 + v2;
}

int test2(const int &v1, const int &v2) {
return v1 + v2;
}

int a = 10;
int b = 20;
test1(a, b);
test1(10, 20); //error

test2(a, b);
test2(10, 20);
  • 可以跟非const引用构成重载
int test2(int &v1, int &v2) {
return v1 + v2;
}

int test2(const int &v1, const int &v2) {
return v1 + v2;
}

int a = 10;
int b = 20;
test2(a, b);
test2(10, 20);
  • 当常引用指向了不同类型的数据时,会产生临时变量,即引用指向的并不是初始化时的那个变量
int age = 10;
const long &ref = age;
age = 30;
// age = 30  ref = 10

//在栈上开辟了单独的空间存放常引用long变量
C7 45 F4 0A 00 00 00 mov         dword ptr [ebp-0Ch],0Ah  

8B 45 F4             mov         eax,dword ptr [ebp-0Ch]  
89 45 F8             mov         dword ptr [ebp-8],eax  
8D 4D F8             lea         ecx,[ebp-8]  
89 4D F0             mov         dword ptr [ebp-10h],ecx 
 
C7 45 F4 1E 00 00 00 mov         dword ptr [ebp-0Ch],1Eh 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值