C++学习笔记(二)

文章介绍了C++中的内联函数,解释了其工作原理、优缺点和使用注意事项。接着讨论了auto关键字的类型推导功能,以及新式for循环的语法和用途。此外,文章还提到了nullptr作为安全的空指针替代宏NULL,并对比了面向过程和面向对象编程的区别。最后,讲解了类的定义、封装和访问限定符的作用。
摘要由CSDN通过智能技术生成

一、内联函数

1.概念

inline修饰的函数成为内联函数。编译时C++的编译器可能会在内联函数被调用的地方将函数展开,不开辟函数栈帧,以提高程序的运行效率。

int Add(int x, int y)
{
    return x + y;
}

int main()
{
    int a = 0;

    printf("%p", &Add);

    a = Add(10, 20);

    return 0;
}

这段代码在调试时,转到反汇编,可以看到,Add函数的地址被调用。

当Add函数被inline修饰为内联函数时,没有为Add函数开辟栈帧,也就是没有调用Add函数。

实际上Add函数在这里被展开了,代码实际上是

a = 10 + 20;

2.优缺点

inline会在编译阶段,将函数调用替换成函数体的内容,这样就优化了函数调用栈帧开辟的消耗,使代码效率更高,运行更快;但是由于将每一处的函数调用都替换为函数体的内容,可能会使代码过长,使目标文件变大。

3.特性

内联说明只是向编译器发出的一个请求,编译器可以选择忽略这个请求”,因为内联展开会使代码过长,目标文件过大,所以编译器一般只会将函数规模较小、非递归、被频繁调用的函数当作内联函数展开。

同时,inline不建议声明和定义分离,因为被inline修饰的函数一旦展开,函数就没有地址了,链接的时候就会找不到。如图所示,编译器会报链接错误。

具体是因为,在编译时,.h的头文件被放到各个.cpp文件中。如下:

在左边的文件中,Add被编译器当作内联函数,在被调用的地方展开,不生成函数地址;但是在右边的文件中,Add也被编译器当作内联函数,在被调用的地方展开,但是由于左边的文件中没有生成Add函数的地址,右边的文件想展开Add但是找不到,所以会报链接错误。

二、auto关键字

如图,auto声明的变量会在编译器编译时推导而出并做替换;

需要注意以下几点:

  1. auto不能用在函数的形参上;

  1. auto不能用来声明数组;

  1. 在一行同时用auto定义多个变量时,变量类型必须一致,否则编译器会报错。

三、for循环

在C++11中,for循环有了另一种用法,如下:

int main()
{
    int arr[] = { 1,2,3,4,5,6,7,8 };

    for (auto e : arr)
    {
        cout << e << endl;
    }
    return 0;
}

for循环后的括号分为2部分,每次遍历都会将:后数组中的一个值赋给:之前定义的变量,在这种情况下for循环会自动判断结束。

四、nullptr

NULL是一个宏,被定义在一个头文件中,但是在C++中可能会被定义成0;

#ifndef NULL
#ifdef __cplusplus
#define NULL   0
#else
#define NULL   ((void *)0)
#endif
#endif

如图所示,在第二次fun函数调用中,本意是想传递指针类型的参数,但是由于定义,变成了传递int类型的参数;为了解决这个问题,在C++11中,引入了nullptr作为关键字,表示空指针。

五、面向过程与面向对象

C语言是一门面向过程的语言,解决问题时偏重于各个步骤;而C++是一门面向对象的语言,通过创建对象,对象之间的各种交互来解决问题。

C语言中结构体只能定义变量,而在C++中,结构体中也可以定义函数。把函数放到结构体中这种方式,在C++中更喜欢用class来代替struct。

六、类

  1. 定义方式

class className
{
    //类体
};//与结构体相似,在定义完类后需要带;

class为定义类的关键字,类似于定义结构体的struct;

className为类的名字;

类体中包含类的成员变量(又称为类的属性)和类的成员函数(又称为类的方法);

类在定义时有两种方式,第一种是声明和定义都放在类体中,但是需要注意的是,如果成员函数在类体中定义,编译器可能会将其视为内联函数。

第二种事声明和定义分离,即在类体中对函数只做声明,在类外实现函数的定义;需要注意的是,由于函数是在类中声明的,在类外定义时需要使用域作用限定符 :: ;

上面代码中还有一个问题,就是在Initi函数中,name和year使用的是类的成员变量还是形式参数,区分不清,因此,可以将代码稍作修改,在类的成员变量定义时加一个特殊的标记以示区分。

七、封装与类的访问限定符

函数就是一种类似于封装的方式,我们在使用库函数时,不需要了解其内部是怎么实现的,只需要使用它,就能完成一个特定的功能。而封装可以简单理解为将多个函数放在一起,可以使用多种功能。拿洗衣服来举例子,如果是函数的话,那么这个洗衣机就只有洗衣服的功能,点击启动,洗完自动关闭。而如果是封装,这个洗衣机就不只会洗衣服,还可以甩干、烘干、干洗等多种功能,只需要按不同的按键就可以。

在上面的Student类的例子中,将两个成员变量与一个成员函数封装起来,对外部只提供Initi接口,但是外部访问不到_name和_year;因为Initi是public,是公开的,而剩下两个,是private,是私有的。

public、protected、private是三个访问限定符;

public修饰的成员可以在类外直接被访问;

protected、private修饰的成员不可以在类外直接被访问;

从一个访问限定符出现开始到下一个访问限定符出现为止,这段内容都是同样的访问权限,到}截止;

class的默认访问权限是private,struct的默认访问权限是public;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王红花x

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值