嗨喽大家好呀,今天给大家带来的是c++必备的过渡知识,希望对大家认识c++有一定的帮助,下面我们来领略命名空间和缺省参数的魅力!
一.c++的过度知识
关于c++的一些关键字
c中的命名冲突
c++的命名空间域介绍
展开命名空间域
展开命名空间域和展开头文件的区别
static关键字
头文件的两种声明
流插入和流提取
二.缺省参数和半缺省参数
今天让我们来学习关于c++我们需要掌握的过度知识,相信经过阅读本篇博客,你一定清晰感觉到c到c++的过度还是比较大的
1. 关于c++的一些关键字
首先我们来介绍一下c++中的关键字,总共有63个关键字
相对于c来说,c++的关键字明显多了不少,今天我们将学习其中的几个关键字,后续我们将会陆续给出,大家不用死记硬背,多用自然就熟悉了
2.c中的命名冲突
#include<stdio.h>
#include<stdlib.h>
int rand = 0;
int main()
{
return 0;
}
大家可以思考一下为什么会报错?相信聪明的同学一眼就可以看出这里发生冲突的原因是因为在C语言中,函数名本质上也是全局的标识符。当你定义int rand = 0;时,你正在尝试在当前作用域(可能是全局作用域,也可能是某个函数或代码块内部)创建一个名为rand的整型变量。如果这是在全局作用域中,那么rand就成为了一个全局变量。
所以我们的c++之父本贾尼博士就在c的基础上增加了命名空间域的这一概念来避免我们自己定义的变量与库函数冲突,下面让我们来走进命名空间域
3.c++的命名空间域介绍
c++用来创建命名空间的关键字是namespace,我们可以在自己命名的空间里随意创建变量,结构以及函数,下面一段代码我来给大家演示一下
namespace ZJ
{
int rand = 0;
struct student
{
int age;
char name;
};
int add(int x, int y)
{
return x + y;
}
}
那么此时就会有小伙伴问了,我们怎么来用这些变量,结构和函数呢?这些是属于局部变量还是全局变量呀?哈哈,慢慢听我来给你讲
划重点咯,下面我给大家介绍一下编辑器的默认查找规则,便于我们理解后续的操作
我们在c语言便了解过局部变量优先原则,在编辑器查找完局部变量才会去查找全局变量,而在c++中这些顺序也不变,默认状态下也不会去查找我们命名空间里的变量。
::叫做域作用限定符,当左边没有东西时,默认访问全局的变量,而当我们在左边加上我们命名空间域的名字时,就会访问域里的变量,类似:
需要注意的是结构体变量的引用我们要注意格式
int main()
{
**struct ZJ::student Class;**
printf("%d\n", ZJ::a);
return 0;
}
4.展开命名空间域
接下来我们将要介绍的是将命名空间域展开,有些小伙伴说我们上面的方法用的挺舒服的呀,干嘛要学展开命名空间域呢?
但是在实际情况中,我们需要多次运用一个域中的同一个函数或者结构,如果一直像上面那种方法。难免会让人觉得麻烦
using namespace ZJ;
只要有了这么一句代码,命名空间作用域下的内容我们就都能直接运用
此时编辑器的查找顺序就变成了局部变量后是全局变量和命名空间域中的变量,注意:全局变量和命名空间中的变量会一起搜索,属于同一优先级
此外:
命名空间可以包含全局变量(即,定义在命名空间中的变量,在命名空间范围内是全局的)。
这些全局变量对于命名空间外部的代码来说,不是直接可见的,除非通过using声明或者完全限定的名字(如namespace_name::variable_name)来访问。
在C++的命名空间中定义的变量不是“局部变量”,因为它们的生命周期不是限制在某个函数或块执行期间。它们更像是被封装在命名空间范围内的全局变量。
当我们在进行项目时文件可能会上百个,我们就需要每几个人一个小组用一个命名空间域的名字,因为多个文件可定义同名的命名空间,这些空间会自动进行合并。
5.展开命名空间域和展开头文件的区别
展开头文件(#include)
1.目的:头文件展开是预处理器的工作,它的目的是将头文件的内容插入到源文件中#include指令所在的位置。这样做通常是为了提供函数声明、类型定义、宏定义等,以便编译器能够正确地编译源文件。
2.时间:这个过程发生在编译的预处理阶段,是实际编译之前的一个步骤。
3.内容:头文件通常包含函数原型、全局变量声明、类型定义(如结构体、联合体、枚举等)、宏定义以及内联函数等。
4.示例:在C或C++中,#include <stdio.h>或#include "myheader.h"会告诉预处理器将指定的头文件内容插入到该位置。
5.作用域:头文件展开后,其中声明的标识符(如函数、全局变量等)的作用域取决于它们在头文件中的声明方式。如果是全局声明,则它们的作用域是全局的;如果是静态声明,则它们的作用域仅限于包含该头文件的源文件。
展开命名空间域(C++中的namespace)
1.目的:命名空间域的展开是编译器的工作,它的目的是确定命名空间内标识符的可见性和作用域。命名空间是C++中的一个特性,用于封装代码并防止命名冲突。
2.时间:这个过程发生在编译阶段,是预处理之后的步骤。
内容:命名空间可以包含类、函数、变量、类型别名、模板以及其他命名空间等。
3.示例:在C++中,namespace MyNamespace { /* … */ }会定义一个命名空间,其中的内容在命名空间外部是不可见的,除非通过using声明或完全限定的名字来访问。
4.作用域:命名空间提供了一种控制标识符作用域的方式。命名空间内的标识符在命名空间外部是不可见的,从而避免了全局作用域中的命名冲突。命名空间可以嵌套,形成层次化的作用域结构。
总结:1.展开头文件是预处理阶段的一个步骤,用于将头文件的内容插入到源文件中。
2.展开命名空间域是编译阶段的一个步骤,用于确定C++中命名空间内标识符的可见性和作用域。
3.两者都涉及到标识符的作用域和可见性,但发生在不同的编译阶段,并且服务于不同的目的。头文件更多地关注于提供编译所需的信息,而命名空间则更多地关注于代码的组织和封装。
6.static关键字
1.局部变量: 当static用于函数内部的局部变量时,它改变了这个变量的存储方式和生命周期。通常,函数内部的局部变量在函数被调用时创建,并在函数返回时销毁。但是,如果一个局部变量被声明为static,那么它只会被初始化一次,并且在函数调用之间保持其值。这样的变量存储在静态存储区,而不是栈区,因此它们的生命周期与程序的生命周期一样长。
2.全局变量: 在全局范围内声明的变量默认是具有外部链接的,这意味着它们可以在其他文件中通过extern关键字被访问。但是,如果全局变量被声明为static,那么它的链接将变为内部的,这意味着它只能在声明它的文件中被访问,而不能被其他文件访问。这有助于封装和减少不同文件之间的耦合。
3.函数: 类似于全局变量,函数默认也是具有外部链接的。但是,如果一个函数被声明为static,那么它只能在声明它的文件中被调用,而不能被其他文件调用。这有助于隐藏实现细节,并只允许通过预定义的接口来访问特定的功能。
7. 头文件的两种声明
**头文件中并不存储变量,头文件只是提供了一种方式,让你可以将声明(和有时定****义)插入到多个源文件中,**头文件展开后,其中声明的标识符(如函数、全局变量等)的作用域取决于它们在头文件中的声明方式。如果是全局声明,则它们的作用域是全局的;如果是静态声明,则它们的作用域仅限于包含该头文件的源文件。
全局声明
假设我们有一个头文件global_header.h,内容如下:
// global_header.h
#ifndef GLOBAL_HEADER_H
#define GLOBAL_HEADER_H
int global_variable; // 全局变量声明
void global_function(); // 全局函数声明
#endif // GLOBAL_HEADER_H
这个头文件中声明了一个全局变量global_variable和一个全局函数global_function。由于它们是全局声明的,所以它们的作用域是全局的。这意味着,在包含了这个头文件的任何源文件中,都可以访问和修改global_variable,也可以调用global_function。
例如,在main.c中:
// main.c
#include "global_header.h"
int main() {
global_variable = 42; // 访问并修改全局变量
global_function(); // 调用全局函数
return 0;
}
在这个例子中,main.c通过包含global_header.h获得了对global_variable和global_function的访问权限。
静态声明
现在,假设我们有一个不同的头文件static_header.h,内容如下:
// static_header.h
#ifndef STATIC_HEADER_H
#define STATIC_HEADER_H
static int static_variable; // 静态变量声明
static void static_function() { // 静态函数声明和定义
// 函数体...
}
#endif // STATIC_HEADER_H
这个头文件中声明了一个静态变量static_variable和一个静态函数static_function。由于它们是静态声明的,所以它们的作用域仅限于包含了这个头文件的每个单独的源文件。这意味着,如果多个源文件都包含了这个头文件,那么每个源文件都会有自己的static_variable副本和自己的static_function副本,这些副本之间是不共享的。
例如,在file1.c和file2.c中分别包含这个头文件:
// file1.c
#include "static_header.h"
void function_in_file1() {
static_variable = 1; // 访问并修改file1.c中的静态变量副本
static_function(); // 调用file1.c中的静态函数副本
}
// file2.c
#include "static_header.h"
void function_in_file2() {
static_variable = 2; // 访问并修改file2.c中的静态变量副本,与file1.c中的副本不同
static_function(); // 调用file2.c中的静态函数副本,与file1.c中的副本不同
}
在这个例子中,file1.c和file2.c都包含了static_header.h,但是它们各自有自己的static_variable和static_function的副本。修改一个源文件中的静态变量不会影响其他源文件中的静态变量。同样地,调用一个源文件中的静态函数也不会影响其他源文件中的静态函数。
8.流插入和流提取
需要注意的是,c++将头文件封装在命名空间域std中,在我们日常练习时,可以直接将头文件全部展开。不过在以后的项目中,还是尽量避免将头文件全部展开
流插入和流提取分别对应c中的printf和scanf函数
9.缺省参数和半缺省参数
这里我们一共需要注意三个问题
1.必须按顺序传,不能跳跃着传
2.半缺省只能从右往左缺省
3.缺省参数在声明给出,不能声明和定义同时给出
#include<iostream>
using namespace std;
namespace ZJ
{
int i = 1;
int j = 2;
int a,b;
}
using namespace ZJ;
int Add(int x,int y)
{
return x + y;
}
void F2(int a = 10, int b = 3, int c = 5)
{
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout << "c = " << c << endl<<endl;
}
int Add(int x = 3, int y = 4);//声明
int main()
{
F2(1, 2, 3);
F2(1, 2 );
F2(1 );
int tmp = Add();
cout << "tmp = " << tmp << endl;
return 0;
}
tmp = 7
而半缺省参数是指在函数声明或定义中,部分变量是缺省参数