【C++初阶】C++入门(一):命名空间&&C++的输入输出&&缺省参数&&函数重载

简介: 【C++初阶】C++入门(一):命名空间&&C++的输入输出&&缺省参数&&函数重载

1.什么是C++

C语言是结构化和模块化的语言,适合处理较小规模的程序。对于复杂的问题,规模较大的程序,需要高度的抽象和建模时,C语言则不合适。为了解决软件危机,20世纪80年代,计算机界提出了OOP(object oriented programming:面向对象) 思想,支持面向对象的程序设计语言应运而生。

 1982年,Bjarne Stroustrup博士在C语言的基础上引入并扩充了面向对象的概念,发明了一种新的程序语言。为了表达该语言与C语言的渊源关系,命名为C++。因此,C++是基于C语言而产生的,它既可以进行C语言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行面向对象的程序设计。

1.1 C++的发展史

1979年,贝尔实验室的本贾尼等人试图分析unix内核的时候,试图将内核模块化于是在C语言的基础上进行扩展,增加了类的机制,完成了一个可以运行的预处理程序,称之为C with classes。语言的发展也是随着时代的进步,在逐步递进的,C++的历史版本:bec111fb2c4d4a08a01b2c196cd9729a.pngC++还在不断地向后发展

1.2 C++关键字(C++98)

C++中总计有63个关键字,这其中有32个是C语言中的关键字:image.png

2.命名空间

在C/C++中,变量、函数和类都是大量存在的,这些变量、函数和类的名称都将作用于全局作用域中,可能会导致很多命名冲突。使用命名空间的目的就是对标识符和名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。

2.1命名空间的定义

定义命名空间,需要使用到 namespace 关键字,后面跟命名空间的名字,然后接一对{}中即为命名空间的成员。

2.1.1命名空间的普通定义

//命名空间的普通定义
namespace N1 //N1为命名空间的名称
{
  //在命名空间中,既可以定义变量,也可以定义函数
  int a;
  int Add(int x, int y)
  {
    return x + y;
  }
}

2.1.2命名空间可以嵌套定义

//命名空间的嵌套定义
namespace N1 //定义一个名为N1的命名空间
{
  int a;
  int b;
  namespace N2 //嵌套定义另一个名为N2的命名空间
  {
    int c;
    int d;
  }
}

2.1.3同一个工程中允许存在多个相同名称的命名空间,编译器最后会将其成员合成在同一个命名空间中dc04ce1788aa4a0bbb01ad1ff5730908.png

12d7e549795d4992b25a9b7a9e28daac.png因此我们不能在相同名称的命名空间中定义两个相同名称的成员。

注意:一个命名空间就定义了一个新的作用域,命名空间中所有内容都局限于该命名空间中。

2.2命名空间的使用

一般变量的搜索情况:局部域->全局域->展开了的命名空间域 or 指定访问命名空间域

现在我们已经知道了如何定义命名空间,那么我们应该如何使用命名空间中的成员呢?

命名空间的使用有以下三种方式:

2.2.1加命名空间名称及作用域限定符

符号“::”在C++中叫做域作用限定符,我们通过“命名空间名称::命名空间成员”便可以访问到命名空间中相应的成员。

:: 的左边为,如果有命名空间域,则限定访问命名空间域中的内容,如果域左边为空,访问的就是全局域,会直接到全局范围内找 :: 右边的变量或其他。

//加命名空间名称及作用域限定符
#include <stdio.h>
namespace N
{
  int a;
  double b;
}
int main()
{
  N::a = 10;//将命名空间中的成员a赋值为10
  printf("%d\n", N::a);//打印命名空间中的成员a
  return 0;
}

2.2.2使用using将命名空间中的成员引入

我们还可以通过“using 命名空间名称::命名空间成员”的方式将命名空间中指定的成员引入。这样一来,在该语句之后的代码中就可以直接使用引入的成员变量了。

//使用using将命名空间中的成员引入
#include <stdio.h>
namespace N
{
  int a;
  double b;
}
using N::a;//将命名空间中的成员a引入
int main()
{
  a = 10;//将命名空间中的成员a赋值为10
  printf("%d\n", a);//打印命名空间中的成员a
  return 0;
}

2.2.3使用using namespace 命名空间名称引入

最后一种方式就是通过”using namespace 命名空间名称“将命名空间中的全部成员引入。这样一来,在该语句之后的代码中就可以直接使用该命名空间内的全部成员了。

//使用using namespace 命名空间名称引入
#include <stdio.h>
namespace N
{
  int a;
  double b;
}
using namespace N;//将命名空间N的所有成员引入
int main()
{
  a = 10;//将命名空间中的成员a赋值为10
  printf("%d\n", a);//打印命名空间中的成员a
  return 0;
}

3.C++中的输入和输出

我们在学C语言的时候,第一个写的代码就是在屏幕上输出一个"hello world",现在我们也应该使用C++来输出:

#include <iostream>
using namespace std;
int main()
{
  cout << "hello world!" << endl;
  return 0;
}

在C语言中有标准输入输出函数scanf和printf,而在C++中有cin标准输入和cout标准输出。在C语言中使用scanf和printf函数,需要包含头文件stdio.h。在C++中使用cin和cout,需要包含头文件iostream以及std标准命名空间。


C++的输入输出方式与C语言相比是更加方便的,因为C++的输入输出不需要增加数据格式控制,例如:整型为%d,字符型为%c。

#include <iostream>
using namespace std;
int main()
{
  int i;
  double d;
  char arr[20];
  cin >> i;//读取一个整型
  cin >> d;//读取一个浮点型
  cin >> arr;//读取一个字符串
  cout << i << endl;//打印整型i
  cout << d << endl;//打印浮点型d
  cout << arr << endl;//打印字符串arr
  return 0;
}

:代码中的endl的意思是输出一个换行符。

4.缺省参数

4.1缺省参数的概念

缺省参数是指在声明或定义函数时,为函数的参数指定一个默认值。在调用该函数时,如果没有指定实参则采用该默认值,否则使用指定的实参。

#include <iostream>
using namespace std;
void Print(int a = 0)
{
  cout << a << endl;
}
int main()
{
  Print();//没有指定实参,使用参数的默认值(打印0)
  Print(10);//指定了实参,使用指定的实参(打印10)
  return 0;
}

4.2缺省参数分类

4.2.1全缺省参数

全缺省参数,即函数的全部形参都设置为缺省参数。

void Print(int a = 10, int b = 20, int c = 30)
{
  cout << a << endl;
  cout << b << endl;
  cout << c << endl;
}

4.2.2半缺省参数

半缺省参数,即函数的参数不全为缺省参数。

void Print(int a, int b, int c = 30)
{
  cout << a << endl;
  cout << b << endl;
  cout << c << endl;
}

注意

 1、半缺省参数必须从右往左依次给出,不能间隔着给。

//错误示例
void Print(int a, int b = 20, int c)
{
  cout << a << endl;
  cout << b << endl;
  cout << c << endl;
}

同时,使用缺省值,必须从右往左连续使用:

eg.全缺省参数这样传参:Func(, 2, ) 就是错误的,传参必须连续,缺省值使用必须从右往左连续使用 !

2、缺省参数不能在函数声明和定义中同时出现

//错误示例
//test.h
void Print(int a, int b, int c = 30);
//test.c
void Print(int a, int b, int c = 30)
{
  cout << a << endl;
  cout << b << endl;
  cout << c << endl;
}

注意:我们平时使用缺省参数,是在声明时给缺省值,定义不能给。

3、缺省值必须是常量或者全局变量。

//正确示例
int x = 30;//全局变量
void Print(int a, int b = 20, int c = x)
{
  cout << a << endl;
  cout << b << endl;
  cout << c << endl;
}

5.函数重载

5.1函数重载的概念

函数重载是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表必须不同。函数重载常用来处理实现功能类似,而数据类型不同的问题。

#include <iostream>
using namespace std;
int Add(int x, int y)
{
  return x + y;
}
double Add(double x, double y)
{
  return x + y;
}
int main()
{
  cout << Add(1, 2) << endl;//打印1+2的结果
  cout << Add(1.1, 2.2) << endl;//打印1.1+2.2的结果
  return 0;
}

注意:形参列表不同是指参数个数参数类型或者参数顺序不同,若仅仅是返回类型不同,则不能构成重载。

5.2函数重载的原理:名字修饰

为什么C++支持函数重载,而C语言不支持函数重载呢?


一个C/C++程序要运行起来都需要经历以下几个阶段:预处理、编译、汇编、链接。


预处理阶段头文件.h的展开、#define 宏的替换、注释的删除,条件编译。->文件名.i

编译阶段将每个源文件的全局范围的变量符号分别进行汇总,生成汇编代码->文件名.s

汇编阶段会给每个源文件汇总出来的符号分配一个地址(若符号只是一个声明,则给其分配一个无意义的地址),然后分别生成一个符号表,汇编代码转换为二进制机器码->文件名.o

最后链接阶段会将每个源文件的符号表进行合并,若不同源文件的符号表中出现了相同的符号,则取合法的地址为合并后的地址(重定位)->文件名.exe/a.out

image.png在C语言中,汇编阶段进行符号汇总时,一个函数汇总后的符号就是其函数名,所以当汇总时发现多个相同的函数符号时,编译器便会报错。


而 C++ 在进行符号汇总时,对函数的名字修饰做了改动,函数汇总出的符号不只是函数的函数名,而是通过其参数的类型和个数以及顺序等信息汇总出 一个符号,这样一来,就算是函数名相同的函数,只要其参数的类型或参数的个数或参数的顺序不同,那么汇总出来的符号也就不同了。image.png

Windows下函数名修饰规则:image.png:不同编译器下,对函数名的修饰不同。

Linux 下函数名修饰规则:

通过下面我们可以看出gcc的函数修饰后名字不变。而g++的函数修饰后变成【_Z+函数名称长度+函数名+类型首字母】image.png总结:

 1、C语言不能支持重载,是因为同名函数没办法区分。而C++是通过函数修饰规则来区分的,只要函数的形参列表不同,修饰出来的名字就不一样,也就支持了重载。

 2、也理解了,为什么函数重载要求参数不同,与返回值没关系,因为返回值在调用的时候不会体现,在编译的时候就会报错了->调用歧义。

//错误
int Func();
double Func();
int main()
{
  Func();//调用歧义
  return 0;
}

5.3 extern “C”

有时候在C++工程中可能需要将某些函数按照C的风格来编译,在函数前加“extern C”,意思是告诉编译器,将该函数按照C语言规则来编译。

注意:在函数前加“extern C”后,该函数便不能支持重载了。

6.总结:

今天我们了解了什么是C++,认识并具体学习了有关命名空间、C++的输入输出、缺省函数、函数重载的知识,开始了C++入门之旅。接下来,我们将继续学习C++的相关知识。希望我的文章和讲解能对大家的学习提供一些帮助。

当然,本文仍有许多不足之处,欢迎各位小伙伴们随时私信交流、批评指正!我们下期见~

c3ad96b16d2e46119dd2b9357f295e3f.jpg

相关文章
|
3月前
|
存储 安全 编译器
【C++打怪之路Lv1】-- 入门二级
【C++打怪之路Lv1】-- 入门二级
39 0
|
3月前
|
自然语言处理 编译器 C语言
【C++打怪之路Lv1】-- C++开篇(入门)
【C++打怪之路Lv1】-- C++开篇(入门)
44 0
|
3月前
|
分布式计算 Java 编译器
【C++入门(下)】—— 我与C++的不解之缘(二)
【C++入门(下)】—— 我与C++的不解之缘(二)
|
3月前
|
编译器 Linux C语言
【C++入门(上)】—— 我与C++的不解之缘(一)
【C++入门(上)】—— 我与C++的不解之缘(一)
|
11天前
|
C++ 芯片
【C++面向对象——类与对象】Computer类(头歌实践教学平台习题)【合集】
声明一个简单的Computer类,含有数据成员芯片(cpu)、内存(ram)、光驱(cdrom)等等,以及两个公有成员函数run、stop。只能在类的内部访问。这是一种数据隐藏的机制,用于保护类的数据不被外部随意修改。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。成员可以在派生类(继承该类的子类)中访问。成员,在类的外部不能直接访问。可以在类的外部直接访问。为了完成本关任务,你需要掌握。
51 18
|
11天前
|
存储 编译器 数据安全/隐私保护
【C++面向对象——类与对象】CPU类(头歌实践教学平台习题)【合集】
声明一个CPU类,包含等级(rank)、频率(frequency)、电压(voltage)等属性,以及两个公有成员函数run、stop。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。​ 相关知识 类的声明和使用。 类的声明和对象的声明。 构造函数和析构函数的执行。 一、类的声明和使用 1.类的声明基础 在C++中,类是创建对象的蓝图。类的声明定义了类的成员,包括数据成员(变量)和成员函数(方法)。一个简单的类声明示例如下: classMyClass{ public: int
37 13
|
11天前
|
编译器 数据安全/隐私保护 C++
【C++面向对象——继承与派生】派生类的应用(头歌实践教学平台习题)【合集】
本实验旨在学习类的继承关系、不同继承方式下的访问控制及利用虚基类解决二义性问题。主要内容包括: 1. **类的继承关系基础概念**:介绍继承的定义及声明派生类的语法。 2. **不同继承方式下对基类成员的访问控制**:详细说明`public`、`private`和`protected`继承方式对基类成员的访问权限影响。 3. **利用虚基类解决二义性问题**:解释多继承中可能出现的二义性及其解决方案——虚基类。 实验任务要求从`people`类派生出`student`、`teacher`、`graduate`和`TA`类,添加特定属性并测试这些类的功能。最终通过创建教师和助教实例,验证代码
37 5
|
11天前
|
存储 算法 搜索推荐
【C++面向对象——群体类和群体数据的组织】实现含排序功能的数组类(头歌实践教学平台习题)【合集】
1. **相关排序和查找算法的原理**:介绍直接插入排序、直接选择排序、冒泡排序和顺序查找的基本原理及其实现代码。 2. **C++ 类与成员函数的定义**:讲解如何定义`Array`类,包括类的声明和实现,以及成员函数的定义与调用。 3. **数组作为类的成员变量的处理**:探讨内存管理和正确访问数组元素的方法,确保在类中正确使用动态分配的数组。 4. **函数参数传递与返回值处理**:解释排序和查找函数的参数传递方式及返回值处理,确保函数功能正确实现。 通过掌握这些知识,可以顺利地将排序和查找算法封装到`Array`类中,并进行测试验证。编程要求是在右侧编辑器补充代码以实现三种排序算法
26 5
|
11天前
|
Serverless 编译器 C++
【C++面向对象——类的多态性与虚函数】计算图像面积(头歌实践教学平台习题)【合集】
本任务要求设计一个矩形类、圆形类和图形基类,计算并输出相应图形面积。相关知识点包括纯虚函数和抽象类的使用。 **目录:** - 任务描述 - 相关知识 - 纯虚函数 - 特点 - 使用场景 - 作用 - 注意事项 - 相关概念对比 - 抽象类的使用 - 定义与概念 - 使用场景 - 编程要求 - 测试说明 - 通关代码 - 测试结果 **任务概述:** 1. **图形基类(Shape)**:包含纯虚函数 `void PrintArea()`。 2. **矩形类(Rectangle)**:继承 Shape 类,重写 `Print
32 4
|
11天前
|
设计模式 IDE 编译器
【C++面向对象——类的多态性与虚函数】编写教学游戏:认识动物(头歌实践教学平台习题)【合集】
本项目旨在通过C++编程实现一个教学游戏,帮助小朋友认识动物。程序设计了一个动物园场景,包含Dog、Bird和Frog三种动物。每个动物都有move和shout行为,用于展示其特征。游戏随机挑选10个动物,前5个供学习,后5个用于测试。使用虚函数和多态实现不同动物的行为,确保代码灵活扩展。此外,通过typeid获取对象类型,并利用strstr辅助判断类型。相关头文件如&lt;string&gt;、&lt;cstdlib&gt;等确保程序正常运行。最终,根据小朋友的回答计算得分,提供互动学习体验。 - **任务描述**:编写教学游戏,随机挑选10个动物进行展示与测试。 - **类设计**:基类
26 3