C++基础语法入门总结

  • C++ 命名空间
    • 如何定义和使用命名空间
  • C++ 输入与输出
  • C++ 缺省参数
  • C++函数重载
    • 名字修饰
    • extern "c"
  • 推荐阅读

C++ 命名空间

其实在C语言中也有命名空间这一说法,只是在C语言中只有全局和函数的命名空间,就是在各自的作用域中使用同名变量、函数等等都不会受到影响。而在C++中,为了避免同名变量、函数、类等的冲突,引入了命名空间,目的是对标识符的名称进行本地化。

如何定义和使用命名空间

命名格式

namespace 命名空间名称
{变量 + 函数}

定义命名空间的三种方式
1、普通的命名空间

namespace N1
{int a = 1;void fun1(){printf("N1: fun1()\n");}
}

2、嵌套的命名空间

namespace N1
{int a = 1;void fun1(){printf("N1: fun1()\n");}//嵌套的命名空间namespace N2{int a = 1;void fun1(){printf("N1: fun1()\n");}}}

3、分段命名空间

namespace N1
{int a = 1;void fun1(){printf("N1: fun1()\n");}
}
//同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。
namespace N1
{int b = 2;void fun2(){printf("N1: fun2()\n");}
}

使用命名空间也有三种方式
一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中。
为了减少冗余,将命名空间N1的定义拿出来:

namespace N1
{int a = 1;void fun1(){printf("N1: fun1()\n");}
}

1、加命名空间名称及作用域限定符::

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

运行结果:

2、使用using将命名空间中成员引入

using N1::a;
using N1::fun1;
int main()
{//using N1::a;//using N1::fun1;printf("N1 : a = %d\n", a);fun1();return 0;
}

运行结果:

3、使用using namespace 命名空间名称引入

using namespace N1;
int main()
{//using namespace N1;通常放到函数之前或者与头文件放一起printf("N1 : a = %d\n", a);fun1();return 0;
}

运行结果:

在工作写大项目时尽量少用第三种使用方法,全部展开后,所有成员都暴露在全局作用域中,会与全局变量等造成命名冲突。而在平时的练习学习当中,建议全部展开。命名是我们自己命名,我们知道会不会造成命名冲突,而且我们练习的程序代码往往不会太大。

C++ 输入与输出

在C语言中,我们通常要输出一个变量和一段字需要用到printf()函数,在printf函数中需要指定变量的格式,输入一个变量的scanf函数也是需要指定格式。而在C++中,有两个流,分别是输出流cout和输入流cin。这两个在C++中替代了printf和scanf,之所以替代,是因为这两个的功能强于printf和scanf函数。接下来我们看看如何使用coutcin

使用cout函数和cin函数都必须要导入头文件<iostream>,注意,这里是没有以.h结尾,这也是C和C++头文件的区别。而在C++中,所有C++头文件中所定义的函数都属于命名空间std中,所以在使用的时候我们都必须导入头文件和使用相对应的命名空间

#include <iostream>
using namespace std;
int main()
{int a = 10;//cout支持连续输出,输出顺序丛左往右//endl:end line相当于c语言中的换行cout << "a = " << a << endl; // a = 10return 0;
}

而对于初学者来说,可能箭头的指向会混乱,我们可以把cout看成是控制台,后面的内容都留进cout,相当于流进控制台,箭头指向控制台<<。打印相对应的内容。

#include <iostream>
using namespace std;
int main()
{int a, b, c;//cin支持连续输出,输出顺序丛左往右cin >> a >> b >> c ;cout << "a = " << a << " b = " << b << " c = " << c << endl;return 0;
}

运行结果:

C++ 缺省参数

C++中的缺省参数,用“备胎”来形容,是最好不过的了。

在C++中,声明或者定义函数时,函数的参数可以给予一个默认值,在调用该函数时如果没有指定实参,在执行函数时会使用默认值。如果指定了实参,这执行函数时会使用指定的实参,这是不是和“备胎”这词意思太相近了。
我们来看以下代码:

#include <iostream>
using namespace std;
void fun1(int a)
{cout << "fun1() : a = " << a << endl;
}void fun2(int a = 10)
{cout << "fun2() : a = " << a << endl;
}int main()
{   //没有缺省值必须传参fun1(1);//有缺省值可以不传参fun2();//有缺省值还传参,使用指定的参数fun2(20);return 0;
}

执行结果:

缺省参数分为两类:全缺省半缺省
全缺省:函数中的参数都给了默认值,即使一个参数也不传也不会报错。
半缺省:函数中的参数有些给了默认值,有些没给。没给默认值的参数必须再传参。

在全缺省中,如果要指定参数,必须是从左往右依次指定。

//全缺省
void fun1(int a = 1, int b = 2, int c = 3)
{cout << "fun1() : a = " << a << " b = " << b << " c = " << c << endl;
}int main()
{fun1();fun1(10);fun1(10, 20);fun1(10, 20, 30);return 0;
}

运行结果:

半缺省函数代码实例:

void fun1(int a, int b, int c = 3)
{cout << "fun1() : a = " << a << " b = " << b << " c = " << c << endl;
}
int main()
{fun1(10,20);fun1(10, 20, 30);return 0;
}

运行结果:

注意
1、在半缺省函数中,缺省的顺序必须是从右往左且连续。

//以下函数都不会通过编译
void fun1(int a, int b = 2, int c){}//不连续
void fun2(int a = 1, int b, int c){}//没有从右向左
void fun3(int a = 1, int b = 2, int c){}

报错结果:

2、缺省参数不能同时出现在声明和定义当中,只能出现在一处,否则编译器无法识别默认值。

//未通过编译
void fun(int a = 1);
void fun(int a = 10){}

报错结果:

3、缺省值支持常量和全局变量

int num = 20;void fun(int a = num)
{cout << "a = " << a << endl;
}
int main()
{fun();  //输出 a = 20return 0;
}

4、在C语言中不支持缺省参数

C++函数重载

函数重载,可以简单理解为“一词多意”。
函数重载:函数重载是用来描述同名函数具有相同或者相似功能,但是参数个数或者类型顺序不一样的函数管理操作。

在C语言中,我们写的相加函数:

int AddInt(int a, int b)
{return a + b;
}char AddChar(char a, char b)
{return a + b;
}double AddDouble(double a, double b)
{return a + b;
}

在这里我们可以看到,他们的功能都是相加两个变量的值,但是他们的函数名不同。因为他们的功能相同,那么我们能不能让它们的函数名都相同呢,无论我们调用什么类型的函数,只要调用Add()函数,并传入我们想要相加的值就可以得到结果呢?
答案是可以的,在C++中,函数支持重载。
我们来看一下下面的代码:

int Add(int a, int b)
{return a + b;
}char Add(char a, char b)
{return a + b;
}double Add(double a, double b)
{return a + b;
}
int main()
{int a = 1, b = 2;cout << "a + b = " << Add(a, b) << endl;char c = 'A', d = '!';cout << "c + d = " << Add(c, d) << endl;double e = 1.01, f = 2.02;cout << "e + f = " << Add(e, f) << endl;return 0;
}

运行结果:

这就达到了我们无论什么类型都只要调用Add()函数,都会相加两个值。

我们知道函数重载可以是函数的参数类型不同,参数的顺序不同也可以构成重载,当传入的参数顺序不同时,编译器可以自动识别参数类型,调用相对应参数类型的函数,实例如下代码:

void fun(int a, char c)
{cout << "fun(int, char)" << endl;
}void fun(char c, int a)
{cout << "fun(char, int)" << endl;
}
int main()
{int a = 10;char c = 'a';fun(a, c);fun(c, a);return 0;
}

执行结果:

函数的参数不同,也可以构成重载:

void fun(int a)
{cout << "fun(int)" << endl;
}void fun(int a, int b)
{cout << "fun(int ,int)" << endl;
}
int main()
{fun(1);fun(1, 2);return 0;
}

运行结果:

总结:函数重载的要求:
1、函数参数的类型不同
2、函数参数的类型顺序不同
3、函数参数的个数不同
注意:函数重载不参考函数的返回值。

那为什么C语言不支持函数重载,而C++支持函数重载呢? --通过名字修饰

名字修饰

名字修饰是针对函数在编译后对函数名称的修饰。这也是为什么函数C++能够支持重载的一个重要原因。
那为什么C语言不支持函数重载呢?

示例代码:

int funtion1(int a, int b)
{return a + b;
}int funtion2(double a, double b)
{return a + b;
}int main()
{funtion(10, 20);funtion(1.01, 2.02);return 0;
}

在vs2019编译环境下
在vs2019编译环境下,函数名称被修饰为<_funtion1>和<_funtion2>,我们可以看出,C语言在vs编译环境下,函数名称修饰只是在原名称前加了_,由于整个编译过程都会经过4个过程,预处理-编译-汇编-链接。在链接的时候,会专门去找名称为_funtion1和_funtion2的函数。如果两个函数同名,那么编译器就无法识别调用哪个函数。

在Linux gcc编译环境下

我们可以看出,在gcc环境下函数名修饰只是它原函数名本身,没有附加其他信息。那在链接的时候肯定就会报错。所以不支持重载。

那C++有怎样的名称修饰让其函数支持重载呢?
示例代码:

int funtion1(int a, int b)
{return a + b;
}int funtion2(double a, double b)
{return a + b;
}int main()
{funtion(10, 20);funtion(1.01, 2.02);return 0;
}

在vs2019编译环境下
名称修饰分别为:

我们可以看到,两个函数的名称修饰,在函数名后面还附加了一下其他信息用来区分同名不同类型的函数。在链接器链接时就能通过函数修饰后的名称来找到相应的函数,从而支持函数的重载。在vs下函数的修饰后的名称可读性比较差,且比较复杂,有兴趣的小伙伴可以上网查查。接下来我们再看看Linux g++编译器对函数名称的修饰。

在Linux g++编译环境下

我们可以看到g++和vs堆函数名称修饰是不一样的,现在我们来了解g++对函数名称的修饰规则。
_Z8funtion1ii:第一个字符_Z是对C++文件的一个修饰,但不起重载作用。数字8是函数的长度,后面接着funtion1是函数的名字,从现在来看也并不起重载的作用。后面两个字母ii表示的是参数的类型。ii是对int的缩写。函数funtion2中后面两个字符是dd,是对double的一个缩写。而两个i是因为有两个int类型的参数。这里要注意的是修饰也参考了参数的顺序。如果函数声明为int funtion3(int a, double b, int c);那么函数修饰后的名称为_Z8funtion3idi。我们也可以从修饰名称规则知道,在函数名相同的情况下,参数的类型、顺序、以及个数的不同,在修饰函数名称后的函数名都不同。所以支持重载,也可以看出函数返回值并没有参与名称修饰,所以函数的重载不以函数返回值作参考。
那我们可以在C++工程中,不想让这个函数重载,有没有办法达到呢,当然可以- -extern “c”

extern “c”

extern "C"作用:在函数前加extern “C”,意思是告诉编译器, 将该函数按照C语言规则来编译。
示例代码:

#include <stdio.h>extern "C" int funtion(int a, int b)
{return a + b;
}double funtion(double a, double b)
{return a +b;
}int main()
{funtion(1, 2);funtion(1.01, 2.02);return 0;
}

g++编译器下的名称修饰

可以看出在C++的函数前加上extern "c"后,编译器并没有对该函数进行名称修饰。这通常用在C/C++混合编程中。特别是在嵌入式编程中,对内存有一定的要求,这时候按照C来编译可以减少内存的开销。

推荐阅读

C++ 基础语法入门总结(二)

C++ C++基础语法入门总结(一)命名空间-输入输出-缺省参数-函数重载相关推荐

  1. C++ C++基础语法入门总结(二)引用-内联函数-C++11新特性

    C++基础语法入门总结 C++引用 再谈引用和指针 C++内联函数 附加C++11新特性 auto关键字 基于范围的for循环 指针空值nullptr C++引用 引用:就是某一变量(目标)的一个别名 ...

  2. 【C++入门第一期】命名空间 缺省参数 函数重载 的使用方法及注意事项

    目录 简介 命名空间 为何会有命名空间 命名空间的定义 嵌套定义 命名空间的使用 作用域限定符 using 将命名空间中某个成员引入 using namespace 将该空间所有成员引入 缺省参数 全 ...

  3. 超详细的C++入门学习(命名空间,缺省参数,内联函数,函数重载等)

    目录 前言 1. C++关键字 2. 命名空间 2.1定义命名空间 2.2使用using将命名空间中某个成员引入 2.3使用using namespace 命名空间名称 引入 3. C++输入& ...

  4. 【C++登山之路之语法高山 】—— 命名空间+缺省参数+函数重载(万字详解,图片演示,结构原理)

    目录

  5. Python基础语法入门篇(一)

    Python基础语法入门篇(二) 1. 注释 在我们工作编码的过程中,如果一段代码的逻辑比较复杂,不是特别容易理解,可以适当的添加注释,以辅助自己 或者其他编码人员解读代码. 注释是给程序员看的,为了 ...

  6. 零基础学C++——黑马程序员课程笔记(C++基础语法入门篇)

    封面来自互联网侵删 视频地址:点击访问 (我这里开发工具选用VSstudio) 此笔记有三个系列: C++基础语法入门篇 C++核心编程篇 点击查看 C++提高编程篇 文章目录 C++初识 变量 常量 ...

  7. Go(一):Go基础语法入门

    Go基础语法入门 第一个go程序 变量 常量 数据类型 字符串处理 `++` `--` 运算符 逻辑运算符 循环 `for ... := range ...` `switch` 死循环 数组的CURD ...

  8. C++基础语法入门(一)

    C++基础语法入门(一) C++基础语法 与语法对应的实例 C++基础语法   笔记是跟着B站黑马视频学习记下来的,https://www.bilibili.com/video/BV1et411b73 ...

  9. 黑马程序员 C++ 基础语法入门 学习记录

    基础语法入门 文章目录 一.初识C++ 1.1 新建项目 1.2 编写项目 1.3 运行程序 1.4 注释 1.5 变量 1.6 常量 1.7 关键字 1.8 标识符命名规则 二.数据类型 2.1 整 ...

最新文章

  1. MindSpore数据集mindspore::dataset
  2. html中空格字符实体整理
  3. mnesia数据库学习笔记四
  4. android中setdate不是静态,为什么当setData()和setType()不起作用时,android intent的setDataAndType()工作正常?...
  5. 文件操作-小文件复制
  6. html元素data属性设置变量,HTML5 自定义属性 data-* 和 jQuery.data 详解
  7. Oracle的resouce、unlimited tablespace 及如何把数据导入不同的表空间
  8. 解析5G背后的核心技术:波束成形
  9. SQL约束脚本的用法
  10. Caused by: java.net.ConnectException: Connection refused: no further information
  11. matlab 机器学习相关函数、api
  12. 小程序快速入门:wxml的使用
  13. .NetCore对接各大财务软件凭证API——金蝶系列(2)
  14. 2018上半年五款最畅销高速数据采集卡,你get了吗?
  15. 五点差分法 matlab,【五点|五点差分法(matlab)解椭圆型偏微分方程】
  16. 关于七牛云上传图片的总结
  17. 华为云——开发者技能测评
  18. matlab的一点内容
  19. iphone开发每日一练【2011-10-11】
  20. tableau计算之(三)表计算——分区/寻址——手动计算/快速计算

热门文章

  1. java 日志技术_java 日志技术汇总(log4j , Commons-logging,.....)
  2. Java业务面考什么_Java程序员面试技巧分享,面考官考查JAVA程序员常用的技术有哪些?...
  3. 同步助手iphone4_88 元淘来的 iPhone 4 降级到 iOS 6,甚至还能跑 “大型游戏”
  4. android评论数据如何返回@用户_教你如何用JavaScript来驯服服务端返回的数据
  5. js定时器异步请求时候 上一个请求没有响应时下一个请求已经开始_关于异步的理解...
  6. 通过jdbc的mysql驱动连接oceanbase mysql模式数据库
  7. Oracle Database 12c 新特性:RAC Cluster Hub Node 和 Leaf Node
  8. 微型计算机pentium或celeron,计算机综合测试答案.doc
  9. Hibernate--什么是持久化?
  10. github团队合作