C++ 入门保姆级教程 (上)

学习目标:

  • 补充c语言语法方面的不足,为后续c++的学习打基础。

学习内容:

1. C++关键字

2. 命名空间

3. C++输入&输出

4. 缺省参数

5. 函数重载


1.C++关键字:

c++总计63个关键字,其中c语言占32个关键字

只要求了解关字个数,如需要具体了解关键字,可根据图表下面链接查找

  • c语言中的关键字
    auto double int strcut

    break

    enum register typedef
    char extern return union
    case else  long with
    const float short unsigned
    continue for signed void
    default goto sizeof volatile
    do if while static

      https://blog.csdn.net/CSDN2133/article/details/122010384

  •  c++关键字在c基础上的延伸(另外31个)
asm try inline bool
dynamic_cast typeid typyname mutable
catch explicit namespace static_cast
export new using class
operator virtual FALSE TRUE
private template const_cast protected
this  public throw wchar_t
friend delete reinterpret_cast

       https://blog.csdn.net/qq_35671135/article/details/88092382


2.命名空间(namespace):

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

展现问题

#include 
#include 

int rand = 10;//重定义已存在中的 rand 函数

// C语言没办法解决类似这样的命名冲突问题,所以C++提出了namespace来解决

int main()
{
 printf("%d\n", rand);
return 0;
}

// 编译后后报错:error C2365: “rand”: 重定义;以前的定义是“函数”
  • 2.1 命名空间定义

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

// Test是命名空间的名字,一般开发中是用项目名字做命名空间名。
// 1. 正常的命名空间定义
namespace Test
{
 // 命名空间中可以定义变量/函数/类型
//变量
 int rand = 10;
//函数
 int Add(int left, int right)
 {
 return left + right;
 }
//类型
 struct Node
 {
 struct Node* next;
 int val;
 };
}

//2. 命名空间可以嵌套
// Test.cpp
namespace N1
{
int a;
int b;
int Add(int left, int right)
 {
     return left + right;
 }
namespace N2
 {
     int c;
     int d;
     int Sub(int left, int right)
     {
         return left - right;
     }
 }
}

//3. 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。
// ps:一个工程中的Test.h和Test.cpp中两个N1会被合并成一个
// Test.h
namespace N1
{
int Mul(int left, int right)
 {
     return left * right;
 }
}

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


  • 2.2 命名空间使用

       2.2.1 命名空间中成员的使用方法

namespace c
{
 // 命名空间中可以定义变量/函数/类型
 int a = 0;
 int b = 1;

 int Add(int left, int right)
 {
 return left + right;
 }

 struct Node
 {
 struct Node* next;
 int val;
 };
}

int main()
{

 // 编译报错:error C2065: “a”: 未声明的标识符
 printf("%d\n", a);
return 0;

}

 2.2.2 命名空间有的三种方式

1.加命名空间名称及作用域限定符(::)

int main()
{
    printf("%d\n", N::a);
    return 0;    
}

(N::a)可以理解为 使用命名空间N作用域中的 a 。

2.使用using namespace 命名空间名称 引入

using namespce N;
int main()
{
    printf("%d\n", N::a);
    printf("%d\n", b);
    Add(10, 20);
    return 0;    
}

3.使用using将命名空间中某个成员引入

        

using N::b;

int main()
{
    printf("%d\n", N::a);
    printf("%d\n", b);
    return 0;    
}

3.C++的 输入&输出

c++ 具体如何表达自己呢?让我们看看接下来的一段代码

#include

// std是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中

using namespace std;
int main()
{
cout<<"Hello world!!!"<

释:#include//带来库

       using namespace std ; // 使用库

说明:

1. 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件 以及按命名空间使用方法使用std

2. cout和cin是全局的流对象,endl是特殊的C++符号,表示换行输出,他们都包含在包含头文件中。

3. >是流提取运算符。cin>>"hello world";

4. 使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动控制格式。 C++的输入输出可以自动识别变量类型。

5. 实际上cout和cin分别是ostream和istream类型的对象,>>和格式,后续编译器已不支持,因 此推荐使用+std的方式。

注意:早期标准库将所有功能在全局域中实现,声明在.h后缀的头文件中,使用时只需包含对应 头文件即可,后来将其实现在std命名空间下,为了和C头文件区分,也为了正确使用命名空间, 规定C++头文件不带.h;旧编译器(vc 6.0)中还支持格式,后续编译器已不支持,因 此推荐使用+std的方式。        

#include 
using namespace std;

int main()
{
   int a;
   double b;
   char c;
     
   // 可以自动识别变量的类型
   cin>>a;
   cin>>b>>c;
     
   cout<

std命名空间的使用惯例:

std是C++标准库的命名空间,如何展开std使用更合理呢?

1. 在日常练习中,建议直接using namespace std即可,这样就很方便。 2. using namespace std展开,标准库就全部暴露出来了,如果我们定义跟库重名的类型/对象/函数,就存在冲突问题。该问题在日常练习中很少出现,但是项目开发中代码较多、规模大,就很容易出现。所以建议在项目开发中使用,像std::cout这样使用时指定命名空间 + using std::cout展开常用的库对象/类型等方式。


4.缺省参数

4.1缺省参数的定义

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

void Func(int a = 0)
{

cout<<"a"<

4.2缺省参数的分类

4.2.1 全缺省参数

void Func(int a = 10, int b = 20, int c = 30)
 {
     cout<<"a = "<void Func(int a, int b = 10, int c = 20)
 {
     cout<<"a = "< //a.h
  void Func(int a = 10);
  
  // a.cpp
  void Func(int a = 20)
 {}
  
  // 注意:如果生命与定义位置同时出现,恰巧两个位置提供的值不同,那编译器就无法确定到底该
用那个缺省值。

5. 函数重载

自然语言中,一个词可以有多重含义,人们可以通过上下文来判断该词真实的含义,即该词被重 载了。

5.1 函数重载概念

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

#include
using namespace std;

// 1、参数类型不同
int Add(int left, int right)
{
 cout << "int Add(int left, int right)" << endl;
 return left + right;
}
double Add(double left, double right)
{
 cout << "double Add(double left, double right)" << endl;
 return left + right;
}

// 2、参数个数不同
void f()
{
 cout << "f()" << endl;
}
void f(int a)
{
 cout << "f(int a)" << endl;
}

// 3、参数类型顺序不同
void f(int a, char b)
{
 cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{
 cout << "f(char b, int a)" << endl;
}
int main()
{
 Add(10, 20);
 Add(10.1, 20.2);
 f();
 f(10);
 f(10, 'a');
 f('a', 10);
 return 0;
}

5.2 C++支持函数重载的原理--名字修饰(name Mangling)

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

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

C++ 入门保姆级教程 (上)_第1张图片

 1. 实际项目通常是由多个头文件和多个源文件构成,而通过C语言阶段学习的编译链接,我们 可  以知道,【当前a.cpp中调用了b.cpp中定义的Add函数时】,编译后链接前,a.o的目标 文件中没有Add的函数地址,因为Add是在b.cpp中定义的,所以Add的地址在b.o中。那么 怎么办呢?

2. 所以链接阶段就是专门处理这种问题,链接器看到a.o调用Add,但是没有Add的地址,就 会到b.o的符号表中找Add的地址,然后链接到一起。

3. 那么链接时,面对Add函数,链接接器会使用哪个名字去找呢?这里每个编译器都有自己的 函数名修饰规则。

4. 由于Windows下vs的修饰规则过于复杂,而Linux下g++的修饰规则简单易懂,下面我们使 用了g++演示了这个修饰后的名字。

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

 采用C语言编译器编译后结果:

C++ 入门保姆级教程 (上)_第2张图片

 结论:在linux下,采用gcc编译完成后,函数名字的修饰没有发生改变。

采用C++编译器编译后结果:

C++ 入门保姆级教程 (上)_第3张图片

结论:在linux下,采用g++编译完成后,函数名字的修饰发生改变,编译器将函数参 数类型信息添加到修改后的名字中。

 Windows下名字修饰规则

对比Linux会发现,windows下vs编译器对函数名字修饰规则相对复杂难懂,但道理都 是类似的,我们就不做细致的研究了。

【扩展学习:C/C++函数调用约定和名字修饰规则--有兴趣好奇的同学可以看看,里面 有对vs下函数名修饰规则讲解】

C/C++的调用约定

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

7. 如果两个函数函数名和参数是一样的,返回值不同是不构成重载的,因为调用时编译器没办 法区分。


c++入门 上篇结

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