C++入门

在这里插入图片描述

欢迎来到Cefler的博客
博客主页:那个传说中的man的主页
个人专栏:题目解析
推荐文章:题目大解析2


目录

  • 命名空间
  • 输入输出
  • 缺省参数
  • 函数重载
    • 为什么c++能支持函数重载
  • 引用
    • 引用使用场景
    • 引用作为传参和返回值的相对于值的效率对比
  • 内联函数
    • 内联函数的特性以及使用注意点
    • 宏的一些问题和内联函数的关系
  • auto关键字
    • auto使用注意点
    • auto不能应用的场景
  • 基于范围的for循环(C++11)
  • 指针空值nullptr(C++11)

命名空间

命名空间概念
命名空间可以被看作是一个包含了一组相关实体的容器。通过将实体放置在命名空间中,可以将它们与其他代码隔离开来,避免命名冲突。

语法就是:

namespace 空间名
{ }

在空间里面,我们也还可以创建这些

  • 变量
  • 数组
  • 结构体
  • 函数
  • 嵌套空间

引用空间⭐️

以上是我们自己创建空间,而我们平常还会引用已经写好的空间。
而这里又分为两种形式

  1. 全部展开
    示例如下
namespace class1
{
	int a = 1;
	int b = 2;
}
using namespace class1;
int main()
{
	cout << a << endl;
	cout << b << endl;

	return 0;
}

上述代码里我创建了一个命名空间,并且对其全部展开,而后能顺利打印空间中的变量a,b。

2.部分展开
示例如下

namespace class1
{
	int a = 1;
	int b = 2;
}
using  class1::a;

这里我们用作用域限定符: :去展开空间中的部分变量a,此时b就无法被访问到了,而且部分展开时,是不用在using 后面加上namespace的。
C++入门_第1张图片
那如果我只部分展开了部分变量,我还想访问其中的其它变量怎么办?
我们仍然可以用作用域限定符: :去针对性的访问空间中的某个变量,比如我想打印b

cout << class1::b << endl;

命名空间和头文件有什么区别?
命名空间和头文件是C++中的两个不同的概念。

命名空间是一种用于组织代码的机制,它可以将相关的函数、类、变量等放置在一个逻辑上的容器中,以避免命名冲突。通过使用命名空间,我们可以将代码模块化,并且可以在不同的命名空间中定义相同名称的实体而不会发生冲突

头文件是一种用于包含代码的文件,通常包含函数、类、变量的声明和定义。头文件通常用于在多个源文件中共享代码,以避免重复编写相同的代码。通过包含头文件,我们可以在源文件中使用头文件中定义的实体,而无需重新编写它们的声明和定义。

因此,命名空间用于组织代码,避免命名冲突,而头文件用于共享代码和声明实体。

输入输出

  1. 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件
    以及按命名空间使用方法使用std。
  2. cout和cin是全局的流对象,endl是特殊的C++符号,表示换行输出,他们都包含在包含< iostream >头文件中。
  3. <<是流插入运算符,>>是流提取运算符。
  4. 使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动控制格式。C++的输入输出可以自动识别变量类型

C++入门_第2张图片

缺省参数

缺省参数概念
缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。
给的实参数目要和缺省数目一样

  • 全缺省参数
    即函数参数中都有给缺省值
void Func(int a = 10, int b = 20, int c = 30)
 {
    
 }
  • 部分缺省参数
void Func(int a , int b = 20, int c = 30)
 {
    
 }

部分缺省参数需要注意

  1. 半缺省参数必须从右往左依次来给出,也不能间隔着给
    错误案例
void Func(int a = 10, int b , int c = 30)
 {
    
 }
  1. 缺省参数不能在函数声明和定义中同时出现
  2. 缺省值必须是常量或者全局变量
  3. C语言不支持(编译器不支持)

函数重载

概念
是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同
函数重载的好处是可以提高代码的可读性和灵活性。通过使用相同的函数名,我们可以根据不同的参数类型来执行不同的操作,而不需要为每种操作定义一个新的函数名。

重载的定义是方法名相同、参数类型不同,满足此条件即可,对返回值没有规定
参数类型相同则不能称为重载,所以参数类型相同、但返回值不同的重载是不合法的

但是函数重载可能会出现调用歧义的问题。如下

#include
using namespace std;
void func(int a)
{
	cout << a << endl;
}
void func(int a,int b = 10)
{
	cout << a + b << endl;
}
int main()
{
	func(4);
	return 0;
}

C++入门_第3张图片

为什么c++能支持函数重载

我们学过,一个程序的运行要进行四个步骤:预处理,编译,汇编,链接
汇编过程就是将汇编代码转换为二进制,并且形成符号表,为的就是后面函数调用时可以根据函数名找到函数。
但是c和c++有不同的函数名修饰规则

  • c语言:编译之后,函数名字的修饰不会发生改变
  • c++: 编译之后,函数名字的修饰会发生改变,编译器会根据函数参数类型,和函数名大小对函数名进行修饰。

通过这里就理解了C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修
饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载

引用

引用概念
引用的实质并不是创建一个新的变量,引用是给一个已经存在的变量取的一个别名,这个别名可以代表这个变量。
引用使用注意要点

  • 引用必须初始化
  • 引用的过程可以平移缩小,但不可以放大
int main()
{
	 const int a = 0;
	 const int& a1 = a;//权限的平移

	 int b = 0;
	 const int& b1 = b;//权限的缩小

	 const int c = 0;
	  int& c1 = c;//权限的放大
	return 0;
}

C++入门_第4张图片
什么情况是放大权限?

如果原变量不允许被改变,则任何可能可以改变原变量的引用都是放大权限。一般原变量也是引用就是可以被允许改变。

  • 一个变量可以有多个别名
  • 引用一旦引用了一个实体,就不能再引用其它的实体,用C语言的话说,就是这个引用的地址从此和所引用的实体绑定(相同),不会再发生变化了,从一而终。
int main() {
	int a = 1;
	int& b = a;
	int& c = b;
	int& d = b;//可以引用多个别名
	cout << &a << endl;
	cout << &b << endl;
	cout << &c << endl;
	cout << &d << endl;
    return 0;
}

C++入门_第5张图片
地址都相同

引用使用场景

1.传参

void Swap(int& left, int& right)
{
   int temp = left;
   left = right;
   right = temp;
}

传参在任何情况下都可以使用
2.做返回值

int& Count()
{
   static int n = 0;
   n++;
   // ...
   return n;
}

做返回值使用情况:返回值在出作用域后仍存在不销毁
为什么呢?
我们上述知道,引用就是和原来的变量绑定在一起(相同地址),所以二者是属于同一本源的,一方改变,另一方也会发生变化,我们知道,函数结束进程后,该函数创建的栈帧就会销毁,里面所定义的变量自然也就不复存在了,这些变量就可能会变成随机值,而如果用引用返回,那么该引用值可能就会发生改变。
所以我们要规避这种风险情况。

引用作为传参和返回值的相对于值的效率对比

结论:引用作为传参和返回值的效率高于值。
也好理解,传值操作只是实参的一份临时拷贝,它在创建栈帧的时候,还要专门创建临时变量,这无疑大大降低了效率。

内联函数

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

如果在函数前增加inline关键字将其改成内联函数,在编译期间编译器会用函数体替换函数的调用。
在Debug模式下查看汇编情况
C++入门_第6张图片
C++入门_第7张图片
这里只展开了函数功能,并未调用函数创建新的栈帧空间。

内联函数的特性以及使用注意点

1.内敛函数本质是以空间换时间
因为它是以函数体代替了函数调用,如果函数体本身大或者展开次数多的话,代码量就会非常大,会导致目标文件很大
2.内联说明只是对编译器的建议,是否采用取决于编译器
如果函数体过大,编译器会忽略内联声明,仍采用函数调用的方法。
所以我们一般只对调用频繁函数体小流程直接不递归的函数进行内联说明,以提高程序运行效率
3.inline不建议声明和定义分离,分离会导致链接错误
这里的声明和定义分离,是指声明和定义分别位于不同的.cpp文件当中。
因为内联函数调用是直接展开,没有地址,链接过程时,内联函数的地址并未进入符号表,找不到地址,自然会出现链接错误。

宏的一些问题和内联函数的关系

宏的优缺点?
优点:
1.增强代码的复用性。
2.提高性能。
缺点:
1.不方便调试宏。(因为预编译阶段进行了替换)
2.导致代码可读性差,可维护性差,容易误用。
3.没有类型安全的检查 。
C++有哪些技术替代宏?

  1. 常量定义 换用const enum
  2. 短小函数定义 换用内联函数

auto关键字

概念
用auto修饰的变量会自动匹配对应的类型。

int a = 0;
auto b = a;

此时auto会自动匹配,b的类型为int
使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编译期会将auto替换为变量实际的类型。

auto使用注意点

  • 用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&
  • 当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。
void TestAuto()
{
    auto a = 1, b = 2; 
    auto c = 3, d = 4.0;  // 该行代码会编译失败,因为c和d的初始化表达式类型不同
}

auto不能应用的场景

1.auto不能用作函数参数,因为编译器无法对函数参数的原类型进行推导
2.auto不能用作声明数组

基于范围的for循环(C++11)

基于范围的for循环只要给出数组名,就会自动遍历数组。

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

注意:for循环迭代的范围必须是确定的

指针空值nullptr(C++11)

nullptr既代表0也是((void*)0)


如上便是本期的所有内容了,如果喜欢并觉得有帮助的话,希望可以博个点赞+收藏+关注❤️ ,学海无涯苦作舟,愿与君一起共勉成长

在这里插入图片描述

你可能感兴趣的:(c++,开发语言)