【C++】C++入门

文章介绍了C++中的内联函数,指出其避免了宏函数的一些问题,提供了代码效率的提升;详细讨论了auto关键字的使用,包括自动类型推导和限制场景;接着讲解了C++11引入的基于范围的for循环,以及如何修改数组元素;最后提到了指针空值nullptr,作为NULL的替代,增强了类型安全性。
摘要由CSDN通过智能技术生成

目录

前言:

一、内联函数:

 内联函数特性:

二、auto关键字:

 auto经常使用于:

auto也可以强制类型:

auto不能推导的场景:

三、基于范围的for循环:

范围for的使用条件:

四、指针空值nullptr:

总结:


前言:

        上一篇文章我们认识C++的关键字、命名空间、C++输出和输入、缺省参数、函数重载、引用,今天我们接着继续学习;

一、内联函数:

        在C语言中,当我们需要频繁调用一个函数时,为了避免在栈开太多空间会使用宏函数来代替函数实现功能。但是在C++中一般不使用宏了,一般都是用const和enum去代替宏常量,用inline代替宏函数了。

为什么C++不是用宏了呢?

        ①宏不支持调试;②没有类型安全检查;③宏只能用来实现一些简单的场景,复杂场景实现不了,就算可以实现,语句也会十分复杂。

我们可以看下列代码

        

#define Add(x,y)((x)+(y))
int main()
{
    //如果将宏定义成这样:#define Add(x,y) (x)+(y)
    int ret=Add(10,2)*3;
    //这时结果为(10)+(2)*3与我们预期的(10+2)*3不一样;
    int a=1;
    int b=3;
    //如果将宏定义成这样:#define Add(x,y) x+y
    int ab=Add(a&b,a|b);
    //这时结果为a&(b+a)|b与我们预期的(a&b)+(a|b)不一样;
    //因为+的优先级比&和|高,所以会先进行。

    return 0;
}

        以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调用时建立栈帧的消耗,内联函数提升程序运行的效率。

下面是内联函数的反汇编:

#include<iostream>
using namespace std;
inline int Add(int a, int b)
{
	return a + b;
}
int main()
{
	int a = 3;
	int b = 2;
	int ret=Add(a, b);
	cout << "ret:" <<ret<< endl;
	return 0;
}

普通函数:

#include<iostream>
using namespace std;
int Add(int a, int b)
{
	return a + b;
}
int main()
{
	int a = 3;
	int b = 2;
	int ret=Add(a, b);
	cout << "ret:" <<ret<< endl;
	return 0;
}

 

 内联函数特性:

①inline是一种以空间换时间的做法,如果编译器将函数当作内联函数处理,在编译阶段会用函数体替换函数调用。

缺陷:可能会使目标文件变大。

优势:没有函数调用时建立栈帧的消耗,提高运行效率。

②inline对于编译器只是一个建议,最终是否会按内联函数处理取决于编译器。

一般内联函数适用于短小频繁调用的函数。

③inline不建议声明和定义分离,分离会导致链接错误,因为inline被展开,就没有地址了,链接会找不到,一般直接定义在头文件。

二、auto关键字:

        使用auto关键字可以让编译器自动推导其类型。

 int main()
 {
     int a = 0;
     auto b = a;
     auto c = &a;
     //typeid().name()可以查看auto推导的是什么类型;
     cout << typeid(b).name() << endl;
     cout << typeid(c).name() << endl;
     return 0;
 }

 auto经常使用于:

1. 类型难于拼写

2. 含义不明确导致容易出错

         我们之前也学过的typedef也可以起到简化代码的作用,但是typedef在一些场景下有很大的缺点,比如:

typedef char* ps;
int main()
{
	const ps p1;
	const ps* p2;
	return;
}

        上面这段代码运行时,会报错:

为什么p1会报错呢?

         这是因为typedef重命名char* 后,p1实际上就是char* const p1;const去修饰p1很明显p1变成了一个常量,而常量的定义必须初始化。

auto也可以强制类型:

int main()
{
	int a = 0l;
	auto* aa = &a;//强制aa是指针类型;

	char c = 'a';
	auto& b = c;//auto后想要其实另一个变量的引用必须加上引用符号
	return 0;
}

ps:

①使用auto定义变量时必须要初始化,因为在编译阶段编译器需要根据初始化表达式来推导auto的实际类型;

②用auto再用一行声明多个变量时,这些变量必须是相同的类型,否则会报错,因为编译器实际支队第一个类型进行推导,然后用推导出来的类型定义其它变量。

auto不能推导的场景:

①auto不能作为函数的参数

②auto不能直接用来声明数组

三、基于范围的for循环:

        对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误,因此C++11中引入基于范围的for循环。for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量,第二部分则是表示迭代的范围,如下:

int main()
{
	int arr[] = { 1,2,3,4,5,6,7 };
	for (auto a : arr)
	{
		cout << a << "" << endl;
	}
	return 0;
}

如果赋值给数组中的元素可直接用a赋值即可:

int main()
{
	int arr[] = { 1,2,3,4,5,6,7 };
	cout << "+=1前:";
	for (auto a : arr)
	{
		cout<< a << " ";
	}
	cout << endl;
	cout << "+=1后:";
	for (auto a : arr)
	{
		a += 1;
		cout << a << " ";

	}
	return 0;
}

 

        但是上面这种做法是不会改变原数组的,如要更改原数组只需要在定义迭代的变量使用引用即可:

int main()
{
	int arr[] = { 1,2,3,4,5,6,7 };
	cout << "+=1前:";
	for (auto a : arr)
	{
		cout<< a << " ";
	}
	cout << endl;
	for (auto& a : arr)
	{
		a += 1;
	}
	cout << "+=1后:";
	for (auto a : arr)
	{
		cout << a << " ";
	}
	return 0;
}

 

范围for的使用条件:

        fot循环迭代的范围必须是确定的,对于数组而言,就是数组中第一个元素和最后一个元素的范围。

四、指针空值nullptr:

        C++中的nullptr实际上是一个补丁,因为C++中的NULL除了bug,如下:
 

void func(int)
{
    cout << "int" << endl;
}
void func(int*)
{
    cout << "int*" << endl;
}
int main()
{
    func(0);
    func(NULL);

    return 0;
}

 按照我们的预期是第一个func输出int,第二func输出int*;但是结果并没有,这是因为在C语言中NULL实际是一个宏(0);所以c++中加了一个关键字nullptr。

void func(int)
{
    cout << "int" << endl;
}
void func(int*)
{
    cout << "int*" << endl;
}
int main()
{
    func(0);
    func(nullptr);

    return 0;
}

 

总结:

        到此我们C++入门就算学完了,C++入门所讲解的都是针对C语言的缺陷进行改进,更多的是语法,会比较枯燥,需要大家动手去练习熟悉它们。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值