首页 > 编程语言 >走进C++——初识与探索

走进C++——初识与探索

时间:2024-09-11 16:54:05浏览次数:13  
标签:const 函数 探索 int namespace C++ 初识 定义

一.C++发展历史

   C++的起源可以追溯到1979年,当时BjarneStroustrup(本贾尼·斯特劳斯特卢普)在⻉尔实验室从事计算机科学和软件⼯程的研究⼯作。⾯对项⽬中复杂的 软件开发任务,特别是模拟和操作系统的开发⼯作,他感受到了现有语⾔(如C语 ⾔)在表达能⼒、可维护性和可扩展性⽅⾯的不⾜。
  1983年,BjarneStroustrup在C语⾔的基础上添加了⾯向对象编程的特性,设计出了C++语⾔的雏形,此时的C++已经有了类、封装、继承等核⼼概念,为后来的⾯向对象编程奠定了基础。这⼀年该语⾔被正式命名为C++。
  在随后的⼏年中,C++在学术界和⼯业界的应⽤逐渐增多。⼀些⼤学和研究所开始将C++作为教学和研究的⾸选语⾔,⽽⼀些公司也开始在产品开发中尝试使 ⽤C++。这⼀时期,C++的标准库和模板等特性也得到了进⼀步的完善和发展。C++ 的标准化⼯作于1989年开始,并成⽴了⼀个ANSI和ISO国际标准化组织的联合标准化委员会。
  1994年标准化委员会提出了第⼀个标准化草案。在该草案中,委员会在保持斯特劳斯特卢普最初定义的所有特征的同时,还增加了部分新特征。在完成C++ 标准化的第⼀个草案后不久,STL是惠普实验室开发的⼀系列软件的统称。它是由 AlexanderStepanov、MengLee和DavidRMusser在惠普实验室⼯作时所开发出来 的。
  在通过了标准化第⼀个草案之后,联合标准化委员会投票并通过了将STL包含到C++标准中的提议。STL对C++的扩展超出C++的最初定义范围。虽然在标准中 增加STL是个很重要的决定,但也因此延缓了C++标准化的进程。
   1997年11⽉14⽇,联合标准化委员会通过了该标准的最终草案。1998年,C++的ANSI/IS0标准被投⼊使⽤。

二.C++和C

C++兼容C的大部分C的大部分语法,很多C的程序在C++环境下一样可以运行。C++中需要把定义⽂件代码后缀改为.cpp,vs编译器看到是.cpp就会调⽤C++编译器编译,linux下要⽤g++编译,不再是gcc。

include<stdio.h>

int main()
{
  printf("hello world");
  return 0;
}

这样的c程序在c++环境下当然可以正常运行,不过c++也有自己的一套语法。

include<iostream>
using namespace std;

int main()
{
   cout<<"hello world\n"<<endl;
   return 0;
}

三.命名空间(namespace)

1.命名空间的意义

在运行一个程序时,你是否也会因习惯或疏忽而导致命名冲突?刚开始学习时我们可能对此没有太多感觉,但当成千上万行代码时,这种情况也许并不少见。所以我们在c++中引入namespace关键字,⽬的是对标识符的名称进⾏本地化,以避免命名冲突或名字污染。

2.namespace的定义

  • 定义命名空间,需要使⽤到namespace关键字,后⾯跟命名空间的名字,然后接⼀对{}即可,{}中即为命名空间的成员。命名空间中可以定义变量/函数/类型等。
  • namespace本质是定义出⼀个域,这个域跟全局域各⾃独⽴,不同的域可以定义同名变量。
  • C++中域有函数局部域,全局域,命名空间域,类域;域影响的是编译时语法查找⼀个变量/函数/类型出处(声明或定义)的逻辑,所有有了域隔离,名字冲突就解决了。局部域和全局域除了会影响编译查找逻辑,还会影响变量的⽣命周期,命名空间域和类域不影响变量⽣命周期。
  • namespace只能定义在全局,当然他还可以嵌套定义。
namespace a
{
   int n = 1;
   namespace b{
   int c = 2;
   }
}
  • 项⽬⼯程中多⽂件中定义的同名namespace会认为是⼀个namespace,不会冲突。
    eg:多个文件里都有叫aabb的namespace,当多个文件合并,多个aabb也会自己合并。
  • C++标准库都放在⼀个叫std(standard)的命名空间中,我们常会见到这样一句代码:
using namespace std;

作用我们在下面讲。

3.namespace的使用

在使用namespace时,我们绕不开一个符号, ::(域作用限定符)。
比如:

using namespace kkk
{
  int a = 1;
}
  int a = 2;
int main()
{
  printf("%d\n", a);
  printf("%d\n", kkk::a);
  return 0;
}

在上述代码中,第一行输出2,第二行输出1。我们可知:

  • ::左边不带域名,则在程序会在全局里找。
  • ::左边带域名,则会去左边的域里找。

在了解完::的使用,我们使⽤命名空间中定义的变量/函数,有三种⽅式:

  • 指定命名空间访问,项⽬中推荐这种⽅式。
  • using将命名空间中某个成员展开,项⽬中经常访问的不存在冲突的成员推荐这种⽅式。
  • 展开命名空间中全部成员,项⽬不推荐,冲突⻛险很⼤,⽇常⼩练习程序为了⽅便推荐使⽤。(也就是我们常见的using namespace std)

四.C++输⼊&输出

  • iostream是InputOutputStream的缩写,是标准的输⼊、输出流库,定义了标准的输⼊、输出对象。
  • std::cin 是istream类的对象,它主要⾯向窄字符的标准输⼊流。
  • std::cout 是ostream类的对象,它主要⾯向窄字符的标准输出流。
    cout一行可输入输出多个,它会自动识别类型。
cout<< a <<" "<<endl; 这个代码正确
cout<<a " " <<endl;   这个代码错误

流插入实质上是一个函数调用,他只允许一个参数,所以第一行代码错误。
流输出也是同理。


  • std::endl 是⼀个函数,流插⼊输出时,相当于插⼊⼀个换⾏字符加刷新缓冲区。endl相当于一个函数put了一个换行符。
  • <<是流插⼊运算符,>>是流提取运算符。(C语⾔还⽤这两个运算符做位运算左移/右移)
  • cout/cin/endl等都属于C++标准库,C++标准库都放在⼀个叫std(standard)的命名空间中,所以要通过命名空间的使⽤⽅式去⽤他们。⼀般⽇常练习中我们可以using namespace std,实际项⽬开发中不建议using namespace std

五.缺省参数

缺省参数顾名思义,就是声明或定义函数时为函数的参数指定⼀个缺省值。若调用函数时传了参数,则使用传的参数,若没传实参,则用默认的缺省值。

eg:
 void Func(int a = 0)
 {
 cout << a << endl;
 }
 int main()
 {
 Func();//打印出0,没有传参时,使⽤参数的默认值
 
 Func(1);//打印出1,传参时,使⽤指定的实参
 
 return 0;
 }

缺省参数也分为全缺省和半缺省参数,顾名思义,全缺省就是所有参数都给一个缺省值,半缺省则是有的参数有缺省值有的参数没有。
tips:

  • 函数声明和定义分离时,缺省参数在声明中给,定义里不给,不然当定义和声明里给的缺省值不一样,则会报错

  • C++规定半缺省必须从右往左缺省, void func (int a, int b = 1)这种形式不可

  • 带缺省参数的函数调⽤,C++规定必须从左到右依次给实参,不能跳跃给实参

六.函数重载

C++⽀持在同⼀作⽤域中出现同名函数,但是要求这些同名函数的形参不同,可以是参数个数不同或者类型不同。这样C++函数调⽤就表现出了多态⾏为,使⽤更灵活。C语⾔是不⽀持同⼀作⽤域中出现同名函数的。

重载也分几种情况:

1. 参数类型不同

#include<iostream>

using namespace std;

int Add (int a,int b)
{
    cout << "int Add(int a, int b)" << endl;
    return a + b
}
double Add(double a,double b)
{
    cout << "double Add(double a, double b)" << endl;
    return a + b
}

函数重载不考虑返回值类型,因为调⽤时也⽆法区分

2.参数个数不同

void f(int c)
 {
    cout << "f(int c)" << endl;
 }
 void f(int a,int b)
 {
    cout << "f(int a,int b)" << 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;
}

tips:

void f1 ()
 {
 cout << "f()" << endl;
  }
void f1(int a = 1)
 {
  cout << "f(int a)" << endl;
 }
//这种属于第二种情况,参数个数不同,构成重载。
  但f()调用的时候会报错,存在歧义。
  编译器会不知道用第一个函数还是第二个函数
 

七.引用

1.引⽤的概念和定义

如同人在社会上,往往伴随着不少外号,比如豹子头林冲,及时雨宋江。引用其实也是,他不是新定义一个变量,而是给已存在的变量取一个别名。,编译器不会为引⽤变量开辟内存空间,它和它引⽤的变量共⽤同⼀块内存空间。

类型& 引⽤别名=引⽤对象
(C++中为了避免引⼊太多的运算符,会复⽤C语⾔的⼀些符号,⽐如前⾯的<<和>>,这⾥引⽤也和取地址使⽤了同⼀个符号&,⼤家注意使⽤⽅法⻆度区分就可以。)

#include<iostream>

using namespace std;

int main()
{
   int a = 0;
   int& b = a;
   int& c = a;  //b和c都是a的别名
   int& d = c;  //也可给c取别名,也相当于a的别名
   return 0;
}

在这里插入图片描述

2.引⽤的特性

  • 引⽤在定义时必须初始化
int a = 0;
int& ra  //编译报错“ra”必须初始化引⽤
int& b = a;  //正确
  • ⼀个变量可以有多个引⽤
  • 引⽤⼀旦引⽤⼀个实体,再不能引⽤其他实体。
int a = 1;
int& b = a;
int c = 2;
b = c;
 // 这⾥并⾮让b引⽤c,因为C++引⽤不能改变指向,
    这里是一个赋值,相当于此时b也就是a的值从1变成了2

3.引用的使用

  • 引⽤在实践中主要是于引⽤传参和引⽤做返回值中减少拷⻉提⾼效率和改变引⽤对象时同时改变被引⽤对象。
  • 引⽤传参跟指针传参功能是类似的,引⽤传参相对更⽅便⼀些
  • 引⽤和指针在实践中相辅相成,功能有重叠性,但是各有特点,互相不可替代。C++的引⽤跟其他语⾔的引⽤(如Java)是有很⼤的区别的,除了⽤法,最⼤的点,C++引⽤定义后不能改变指向,Java的引⽤可以改变指向。

4.const引用

  • const引用注意,权限可以缩小,但不可以放大,如:
const int a = 20;
int& b = a; //不行,这里将a的权限放大了,会报错
const int& b = a;  //可以

int c = 20;
const int& rc = c;  //可以,这里是缩小b的权限
//c++也等同于rc++,但不可直接给rc++
  • 对于一些如int a = 30 的常量,我们不能直接int& b = a,但加上const就可以:const int& b = a.对于具有常性的对象,我们往往要使用const引用。
  • 在C++中,临时对象就是编译器需要⼀个空间暂存表达式的求值结果时临时创建的⼀个未命名的对象,⽽C++规定临时对象具有常性。所以不仅是常量,临时对象也需要使用const引用。
int a = 10;
const int& ra = a; //可以
int& b = a * 3;  //编译报错: “初始化”: ⽆法从“int”转换为“int &”
const int& rb = a*3;  //编译通过
//一个表达式如a * 3 得到的是一个临时对象,所以要用const

double c = 12.11;
int& rc = c;  // 编译报错:“初始化”: ⽆法从“double”转换为“int &” 
const int& rd = d;  //编译通过
//这里进行了强制类型转换,将double转化成int型,在类型转换中会产⽣临时
对象存储中间值,也就是临时对象,所以要用const

5.指针和引⽤的关系

  • 语法概念上引⽤是⼀个变量的取别名不开空间,指针是存储⼀个变量地址,要开空间。
  • 引⽤在定义时必须初始化,指针建议初始化,但是语法上不是必须的。
  • 引⽤在初始化时引⽤⼀个对象后,就不能再引⽤其他对象;⽽指针可以在不断地改变指向对象。
  • 引⽤可以直接访问指向对象,指针需要解引⽤才是访问指向对象。
  • sizeof中含义不同,引⽤结果为引⽤类型的⼤⼩,但指针始终是地址空间所占字节个数(32位平台下占4个字节,64位下是8个字节)
  • 指针很容易出现空指针和野指针的问题,引⽤很少出现,引⽤使⽤起来相对更安全⼀些。

八.内联函数inline

  • ⽤inline修饰的函数叫做内联函数,编译时C++编译器会在调⽤的地⽅展开内联函数,这样调⽤内联函数就需要建⽴栈帧了,就可以提⾼效率
  • inline对于编译器⽽⾔只是⼀个建议,也就是说,你加了inline编译器也可以选择在调⽤的地⽅不展开,不同编译器关于inline什么情况展开各不相同,因为C++标准没有规定这个。inline适⽤于频繁调⽤的短⼩函数,对于递归函数,代码相对多⼀些的函数,加上inline也会被编译器忽略。
  • C语⾔实现宏函数也会在预处理时替换展开,但是宏函数实现很复杂很容易出错的,且不⽅便调试,C++设计了inline⽬的就是替代C的宏函数。
  • inline不建议声明和定义分离到两个⽂件,分离会导致链接错误。因为inline被展开,就没有函数地址,链接时会出现报错。
  • 由于涉及到汇编语言,且前期对于inline函数没有过多需求,我们就先不展开说了。

九.nullptr

nullptr实际上就相当于c语言中的NULL,那为什么在c++中我们要换掉NULL而使用nullptr呢。实际上,NULL是一个宏,在传统的C头⽂件(stddef.h)中,可以看到如下代码:
在这里插入图片描述
我们可以看到,所以C++中NULL可能被定义为字⾯常量0,或者C中被定义为⽆类型指针(void*)的常量。但不管被定义成什么,在使⽤空值的指针时,都不可避免的会遇到⼀些⿇烦,比如:

 using namespace std;
 void f(int x)
 {
 cout << "f(int x)" << endl;
 }
 void f(int* ptr)
 {
 cout << "f(int* ptr)" << endl;
 }
 int main()
 {
    f(0);
    f(NULL);  
    //本想通过f(NULL)调⽤指针版本的f(int*)函数,但是由于
      NULL被定义成0,调⽤了f(int x),因此与程序的初衷相悖。
      
    f((int*)NULL);  //这样不行,会报错
    
    f(nullptr); //成功调用void f (int * ptr)函数
    
    return 0;
 }

所以在c++中,我们引⼊nullptr,nullptr是⼀个特殊的关键字,nullptr是⼀种特殊类型的字⾯量,它可以转换成任意其他类型的指针类型。用nullptr定义空指针可以避免类型转换的问题,因为nullptr只能被隐式地转换为指针类型,⽽不能被转换为整数类型。

标签:const,函数,探索,int,namespace,C++,初识,定义
From: https://blog.csdn.net/2301_80171129/article/details/142108981

相关文章

  • C++ 类继承
    一、继承1.继承的概念和意义继承机制是面向对象程序设计使代码可以复用的最重要的手段,它允许我们在保持原有类特性的基础上进行扩展,产生新的类,称子类。例如下面的Student类和Teacher类,它们都有人名,性别,电话,年龄,住址等信息。不同的是Student类有学号之分,而老师有职称之......
  • 中国电科网安校园招聘:C++工程师
      本文介绍2024届秋招中,中国电子科技网络信息安全有限公司的C/C++开发工程师岗位一面的面试基本情况、提问问题等。  2024年10月投递了中国电子科技网络信息安全有限公司的C/C++开发工程师岗位,并不清楚所在的部门。目前完成了一面,在这里记录一下一面经历。  这一次面试面......
  • C++最强功能之一指针
    最是人间留不住,朱颜辞镜花辞树。                            ——《蝶恋花·阅尽天涯离别苦》【清】王国维今天我们来说一说这个C++区别其他语言最明显的功能,指针。C++的指针可以说是功能强大,很多游戏的外挂中核......
  • C++ 不要将有符号整数和无符号整数相加
    一有符号整数和无符号整数相加时,把负数转换成无符号数类似于直接给无符号数赋一个负值,结果等于这个负数加上无符号数的模。unsignedintn=300;intm=-500;cout<<m+m<<'\n';cout<<n+m<<'\n';输出:-1000//正确4294967096//错误结果做个类型......
  • 探索Go语言中的随机数生成、矩阵运算与数独验证
    1.Go中的随机数生成在许多编程任务中,随机数的生成是不可或缺的。Go语言通过math/rand包提供了伪随机数生成方式。伪随机数由种子(seed)决定,如果种子相同,生成的数列也会相同。为了确保每次程序运行时产生不同的随机数,我们通常使用当前时间作为种子。示例1:简单的随机数生......
  • 探索前端可视化大屏:创造令人惊叹的数据可视化体验
    介绍......
  • 深入探索从ES6到ES2023
    从ES6到ES2023,我们深入探索ECMAScript(简称ES)的演变与发展,了解这一JavaScript标准背后的技术革新和进步。ECMAScript作为JavaScript的标准化版本,每年都在不断推出新版本,为开发者带来更加丰富和强大的功能。本文将从ES6的引入开始,逐步介绍到最新的ES2023,同时探讨这些新特性对......
  • 南沙C++信奥老师解一本通题:1203:扩号匹配问题
    ​【题目描述】在某个字符串(长度不超过100)中有左括号、右括号和大小写字母;规定(与常见的算数式子一样)任何一个左括号都从内到外与在它右边且距离最近的右括号匹配。写一个程序,找到无法匹配的左括号和右括号,输出原来字符串,并在下一行标出不能匹配的括号。不能匹配的左括号用"$"标......
  • C++题目收集2
    这是本专栏的的第二篇收录集,我们一起来看一看那些有意思的题目,拓宽自己的思路。本期的题目有一些难,所以数目少一点。题目一:约瑟夫环#include<iostream>#include<vector>intjosephus(intn,intm){std::vector<int>people(n);for(inti=0;i<n;++i)......
  • 《C++ Primer Plus》学习day3
    C++11新增的内容:char16_t和char32_tchar16_t:无符号,16位,使用前缀u表示char_16字符常量和字符串常量;char32_t:无符号,32位,使用前缀U表示char32_t常量浮点类型C++有三种浮点类型:float、double、longdouble头文件cfloat中对对浮点数进行了限制:比如最低有效位......