C++入门的基础

幸福比傲慢更容易蒙住人的眼睛。 ——大仲马


C++入门

  • 1、属于C++的关键字
    • 1、1、C++从何而来
    • 1、2、C++关键字(C++98)
  • 2、命名空间
    • 2、1、命名空间的定义
    • 2、2、命名空间使用
  • 3、C++输入和输出
  • 4、缺省参数
    • 4、1、缺省参数概念
    • 4、2、缺省参数分类
  • 5、函数重载
    • 5、1、函数重载概念
  • 6、引用
    • 6、1、引用概念
    • 6、2、引用特性
    • 6、3、常引用
    • 6、4、使用场景
    • 6、5、传值、传引用效率比较
    • 6、6、引用和指针的区别
  • 7、内联函数
    • 7、1、概念
    • 7、2、特性
    • 7、3、inline细节
  • 8、auto关键字(C++11)
    • 8、1、auto介绍
    • 8、2、auto使用规则

1、属于C++的关键字

1、1、C++从何而来

为什么会出现C++呢?为什么C++的关键字和C语言相对比起来,有着不少的增加?
其实想要搞明白为什么会出现这种状况,首先要明白的是C++是祖师爷用C语言的过程中,饱受C语言中一些限制的诟病,在C语言的基础上增加的一个更牛的系统。在这里插入图片描述
Bjarne Stroustrup就是他创建的C++。
所以,对于学习过C语言的人来说,C++是一款不可多得的好用的语言。在基础之上为我们解决一些C语言不能够很好处理的问题,给我们节约时间,拥有更多的库,不再像C语言那样,还需要我们去造轮子。

1、2、C++关键字(C++98)

在这个版本中,总计是63个关键字,而C语言的关键字是32个,有了很大的提升。相对于C来说,提升了很多,也更方便了。
在这里插入图片描述

2、命名空间

为什么要有命名空间的这一术语?因为在C/C++中,变量,函数以及类都是大量存在的,这些都将存储于全局作用域,那么就可能会引起冲突。使用命名空间,就可以将标识符的名称本地化,从而避免命名冲突,而运用命名空间来解决问题的关键字就是namespace。

#include <stdio.h>
#include <stdlib.h>
int rand = 10;
// C语言没办法解决类似这样的命名冲突问题,所以C++提出了namespace来解决
int main()
{
 printf("%d\n", rand);
return 0;
}
// 编译后后报错:error C2365: “rand”: 重定义;以前的定义是“函数”

这就是很好的证明,C++之中namespace的便捷。

2、1、命名空间的定义

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

// hehe是命名空间的名字,一般开发中是用项目名字做命名空间名。
// 我们上课用的是bit,大家下去以后自己练习用自己名字缩写即可,如张三:zs
// 1. 正常的命名空间定义
namespace hehe
{
 // 命名空间中可以定义变量/函数/类型
 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、命名空间使用

那么有了命名空间,该如何去使用不同作用域的成员呢?

namespace bit
{
 // 命名空间中可以定义变量/函数/类型
 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;
}

那我们该怎么去找到这里的a呢?
命名空间的三种方法:
1、在使用前在上空间名称以及作用域限定符

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

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

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

3、使用using namespace+命名空间 引用

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

通常而言,第三种在大型的组合团队中不要使用,因为标准库就全部暴露出来了,如果我们定义跟库重名的类型/对象/函数,就存在冲突问题。但是对于正常的人来说,写一些正常的程序,还是建议使用第三种的,不仅方便,还能理解到命名空间关键字的意义。

3、C++输入和输出

对于C来说的“hello world ”是我们学习的第一句话,那么关于C++来说,我们该怎么去让他在屏幕上显示出来呢?

#include<iostream>
// std是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中
using namespace std;
int main()
{
cout<<"Hello world!!!"<<endl;
return 0;
}

说明:
1、 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件
以及按命名空间使用方法使用std。
2. cout和cin是全局的流对象,endl是特殊的C++符号,表示换行输出,他们都包含在包含<
iostream >头文件中。
3. <<是流插入运算符,>>是流提取运算符。
4. 使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动控制格式。
C++的输入输出可以自动识别变量类型。
5. 实际上cout和cin分别是ostream和istream类型的对象,>>和<<也涉及运算符重载等知识,
这些知识我们我们后续才会学习,所以我们这里只是简单学习他们的使用。
注意: 早期标准库将所有功能在全局域中实现,声明在.h后缀的头文件中,使用时只需包含对应头文件即可,后来将其实现在std命名空间下,为了和C头文件区分,也为了正确使用命名空间,规定C++头文件不带.h;旧编译器(vc 6.0)中还支持<iostream.h>格式,后续编译器已不支持,因此推荐使用+std的方式。

4、缺省参数

4、1、缺省参数概念

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

void Func(int a = 0)
{
 cout<<a<<endl;
}
int main()
{
 Func();     // 没有传参时,使用参数的默认值
 Func(10);   // 传参时,使用指定的实参
return 0;
}

4、2、缺省参数分类

全缺省参数

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

半缺省参数

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

注意:
1、半缺省参数不是指只有一半,而是必须从左往右依次来给出,不能间隔。
2、缺省参数不能再函数声明和定义中同时出现。

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

3、缺省值必须是常量或全局变量
4、C语言不支持(编译器不支持)

5、函数重载

在现实世界,一个词常常有着不同含义,我们可以同上下问之间的关系来判断词的真正含义,即使该词重载了。
重载从词语上的意思来说,从我的感觉来说,也可以看作是,重复的载入
以前有一个笑话,国有两个体育项目大家根本不用看,也不用担心。一个是乒乓球,一个是男足。前者是“谁也赢不了!”,后者是“谁也赢不了!

5、1、函数重载概念

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

#include<iostream>
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;
}

6、引用

6、1、引用概念

引用不是创建一个新的变量,而是给已经存在的变量取别名,变量和变量的别名共同使用一块内存空间。
引用相当于给别人起外号,如果本人做了什么,或者说是别名做了什么,都是改变同一个人。
比如:李逵你吃过了吗,李逵吃过了,那黑旋风一定也是吃过了。
类型& 引用变量名(对象名)=引用实体

void TestRef()
{
    int a = 10;
    int& ra = a;//<====定义引用类型
    printf("%p\n", &a);
    printf("%p\n", &ra);
}

注意:引用类型必须是和实体是同种类型的

6、2、引用特性

1、引用并不能在定义的时候不初始化。
2、一个变量可以有多个引用
3、引用一旦引用一个实体,再也不能引用其他实体。

void TestRef()
{
   int a = 10;
   // int& ra;   // 该条语句编译时会出错
   int& ra = a;
   int& rra = a;
   printf("%p %p %p\n", &a, &ra, &rra);  
}

6、3、常引用

void TestConstRef()
{
    const int a = 10;
    //int& ra = a;   // 该语句编译时会出错,a为常量
    const int& ra = a;
    // int& b = 10; // 该语句编译时会出错,b为常量
    const int& b = 10;
    double d = 12.34;
    //int& rd = d; // 该语句编译时会出错,类型不同
    const int& rd = d;
}

6、4、使用场景

1、做参数

void TestConstRef()
{
    const int a = 10;
    //int& ra = a;   // 该语句编译时会出错,a为常量
    const int& ra = a;
    // int& b = 10; // 该语句编译时会出错,b为常量
    const int& b = 10;
    double d = 12.34;
    //int& rd = d; // 该语句编译时会出错,类型不同
    const int& rd = d;
}

2、做返回值

int& Count()
{
   static int n = 0;
   n++;
   // ...
   return n;
}

下面代码中,输出的结果是什么呢?

int& Add(int a, int b)
{
    int c = a + b;
    return c;
}
int main()
{
    int& ret = Add(1, 2);
    Add(3, 4);
    cout << "Add(1, 2) is :"<< ret <<endl;
    return 0;
}

在这里插入图片描述

6、5、传值、传引用效率比较

以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。

#include <time.h>
struct A{ int a[10000]; };
A a;
// 值返回
A TestFunc1() { return a;}
// 引用返回
A& TestFunc2(){ return a;}
void TestReturnByRefOrValue()
{
 // 以值作为函数的返回值类型
 size_t begin1 = clock();
 for (size_t i = 0; i < 100000; ++i)
 TestFunc1();
 size_t end1 = clock();
 // 以引用作为函数的返回值类型
 size_t begin2 = clock();
 for (size_t i = 0; i < 100000; ++i)
 TestFunc2();
 size_t end2 = clock();
 // 计算两个函数运算完成之后的时间
 cout << "TestFunc1 time:" << end1 - begin1 << endl;
 cout << "TestFunc2 time:" << end2 - begin2 << endl;
}

通过上述的代码比较,不难发现传值和指针在作为传参以及返回值类型上面的效率相差很大。

6、6、引用和指针的区别

语法层面上引用就是别名,没有独立的空间,和引用的实体共同用一块空间。
但是,底层实现上实际是有空间的,因为引用是按照指针的方式去实现的。因为C++就是在C的基础上来进行进化的。

int main()
{
int a = 10;
int& ra = a;
ra = 20;
int* pa = &a;
*pa = 20;
return 0;
}

我们通过什么知道这两个是一样的呢?当然是通过计算机编译器的底层汇编来看啊。
在这里插入图片描述
引用和指针的不同点:
1、引用概念上的定义是变量的别名指针存储一个变量的地址
2、引用在定义的时候就必须初始化,指针没有要求。
3、引用在初始化时引用一个实体之后,就不能引用其他实体,而指针可以在任何时候指向任何一个同类型的实体。
4、没有NULL引用,但是有NULL指针。
5、sizeof的计算不同,引用的结果为引用类型的大小,但是指针始终是地址空间所占字节个数(32位平台下占4个字节)
6、引用自加1,即实体加1。指针自加则是向后偏移一个类型的大小。
7、有多级指针,但是没有多级引用
8、访问方式不同,指针需要显示解引用,引用编译器自己处理。
9、引用比指针使用起来相对来说更安全。

7、内联函数

7、1、概念

在函数最开始的时候用inline修饰的函数叫做内联函数,C++编译器会在调用内联函数的地方展开。但是由于编译器的不断提升,现在的编译器已经会判断函数是否应该展开,如果太长也不会展开的。那为什么需要**inline呢?**那是因为不需要调用函数,也就意味着没有函数调用建立栈的开销,内联函数提升程序运行的效率。
在这里插入图片描述
这是正常的函数调用。在这里插入图片描述
而这时内联函数的展开。

7、2、特性

1、 inline函数是一种空间换时间的做法,如果编译器将函数当作内联函数处理,在编译阶段,会用函数体替换函数调用
2、 inline对于编译器来说只是一个建议,不同的编译器实现的机制可能不同,一般来说:函数规模较小(函数不是很长,具体还是取决于编译器)、不是递归且频繁的调用的函数采用inline,否则编译器将会忽略inline的特性。
在这里插入图片描述
3、 inline不建议声明和定义分离 ,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。

7、3、inline细节

首先看一下宏和函数的区别。
请添加图片描述
宏的优点和缺点在上述的图片中已经很清楚了,那么有没有什么办法能够在这些的优点上进行对缺点的改变?
C++中的可以代替宏的方案
1、常量定义 换成const enum
2、短小函数定义 换成内联函数

8、auto关键字(C++11)

随着程序的复杂化,类型的使用也将会是多样化。这就导致
1、类型难于拼写
2、含义不明导致出错

8、1、auto介绍

auto不再是一个存储类型指示符,而是作为一
个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得

int TestAuto()
{
return 10;
}
int main()
{
int a = 10;
auto b = a;
auto c = 'a';
auto d = TestAuto();
cout << typeid(b).name() << endl;
cout << typeid(c).name() << endl;
cout << typeid(d).name() << endl;
//auto e; 无法通过编译,使用auto定义变量时必须对其进行初始化
return 0;
}

==注意:==使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto
的实际类型。因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编
译期会将auto替换为变量实际的类型

8、2、auto使用规则

1、 auto与指针和引用结合使用
用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须
加&

2、 同一行定义多个变量时,所有的变量必须是相同类型。
3、 auto不能作为函数的参数。同时,也不能声明数组。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/370701.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PHP框架详解 - symfony框架

首先说一下为什么要写symfony框架&#xff0c;这个框架也属于PHP的一个框架&#xff0c;小编接触也是3年前&#xff0c;原因是小编接触Golang&#xff0c;发现symfony框架有PHP框架的东西也有Golang的东西&#xff0c;所以决定总结一下&#xff0c;有需要的同学可以参看小编的G…

yolov1到v8的变化

目录 1.YOLO介绍&#xff1a;1.变化&#xff1a;小结&#xff1a; 1.YOLO介绍&#xff1a; YOLO&#xff08;You Only Look Once&#xff09;是一种流行的目标检测算法&#xff0c;它的版本从YOLOv1到YOLOv8经历了多次改进。以下是YOLOv1到YOLOv8的一些不同之处和改变&#xf…

快来使用Portainer让测试环境搭建飞起来吧

Portainer是Docker的图形化管理工具&#xff0c;提供状态显示面板、应用模板快速部署、容器镜像网络数据卷的基本操作&#xff08;包括上传下载镜像&#xff0c;创建容器等操作&#xff09;、事件日志显示、容器控制台操作、Swarm集群和服务等集中管理和操作、登录用户管理和控…

PM圆桌派:同事不愿意告诉你的职场套路有哪些?

职场是社会的缩影&#xff0c;想要崭露头角&#xff0c;获得更多升职加薪的机会&#xff0c;就不要做着和多数人一样的事情&#xff0c;却期待着不一样的结果。 职场上有很多潜在的规则&#xff0c;要会做事&#xff0c;也要会说话&#xff0c;更要会做人。如果不懂规则&#…

Python 数据可视化:配色方案

1、引言 在这篇文章中&#xff0c;我们将研究Python的一些配色方案&#xff0c;主要是Seaborn库。这将采用 Python Notebook 格式&#xff0c;其中包括绘图的代码。 2、实验数据 首先导入必要的库&#xff1a; import pandas as pd import seaborn as sns import matplotlib…

【Vue】3-2、组合式 API

一、setup 选项 <script> export default {/*** 1、setup 执行时机早于 beforeCreate* 2、setup 中无法获取 this* 3、数据和函数需要在 setup 最后 return&#xff0c;才能在模板中使用* 4、可以通过 setup 语法糖简化代码*/setup(){// console.log(setup function, thi…

Flink容错机制

目录 一&#xff0c;检查点&#xff1a; 二&#xff0c;保存点&#xff1a; ①版本管理和归档存储&#xff1a; ②更新Flink版本&#xff1a; ③更新应用程序&#xff1a; ④调整并行度&#xff1a; ⑤暂停应用程序&#xff1a; Flink容错机制 一&#xff0c;检查点&#xff…

RedHat8.4安装邮件服务器

一、配置发件服务器 1.1 根据现场IP&#xff0c;配置主机名 vim /etc/hosts 192.168.8.120 mail.test.com 将主机名更改为邮件服务器域名mail.test.com 1.2 关闭防火墙&#xff0c;禁止开机启动 systemctl stop firewalld systemctl disable firewalld 1.3 关闭selinux v…

java之ReentrantLock

在讲RentrantLock之前需要先讲一下AQS和LockSupport&#xff0c;因为rentrantLock底层是用AQS实现的&#xff0c;而AQS中获取阻塞和唤醒底使用LockSupport实现的。 1、LockSupport实现 下面代码中&#xff0c;LockSupport.park方法是当前线程等待&#xff0c;直到获得许可&am…

React Native学习记录

一、创建RN项目的时候是空文件夹的问题 1.使用npx react-native init RNDemos初始化项目的时候&#xff0c;会报错&#xff0c;模版错误&#xff0c;然后创建出来一个空的文件夹 2.如果出现这种情况&#xff0c;需要设置npm install -g react-native-cli 3.安装完成以后再次初…

Postgres与DynamoDB:选择哪个数据库

启动新项目时需要做出的决定之一是使用哪个数据库。如果您使用的是Django这样的包含电池的框架&#xff0c;那么没有理由再三考虑。选择一个受支持的数据库引擎&#xff0c;就可以了。另一方面&#xff0c;如果你使用像FastAPI或Flask这样的微框架&#xff0c;你需要自己做出这…

聚簇索引、回表与覆盖索引

聚簇索引一般指的是主键索引&#xff08;如果存在主键索引的话&#xff09;。 作为一个正常开发&#xff0c;建表时主键肯定是必须的。 而即使如果表中没有定义主键&#xff0c;InnoDB 会隐式选择一个唯一的非空索引代替。 所以我们就直接含糊点说&#xff1a; 聚簇索引就是…

crmebAI名片小程序全开源全端uniapp

应用介绍 AI名片小程序是一种基于人工智能技术的数字化智能名片&#xff0c;具有多种功能和特点。以下是AI名片小程序的简介&#xff1a; 智能化管理&#xff1a;AI名片小程序具备智能化的管理系统&#xff0c;用户可以方便地管理名片信息&#xff0c;包括个人信息、职位、公司…

jmeter-02切换中文,改为白色背景

文章目录 一、切换中文问题&#xff1a;jmeter设置中文后无法保存&#xff0c;下次启动还是英文 二、改为白色背景 一、切换中文 问题&#xff1a;jmeter设置中文后无法保存&#xff0c;下次启动还是英文 解决办法&#xff1a; 在jmeter路径下找到文件jmeter.bat开启编辑模式&…

如何在Shopee平台上进行手机类目选品?

在Shopee平台上进行手机类目的选品是一个关键而复杂的任务。卖家需要经过一系列的策略和步骤&#xff0c;以确保选品的成功和销售业绩的提升。下面将介绍一些有效的策略&#xff0c;帮助卖家在Shopee平台上进行手机类目选品。 先给大家推荐一款shopee知虾数据运营工具知虾免费…

指针的学习2

目录 数组名的理解 使用指针访问数组 一维数组传参的本质 冒泡排序 二级指针 指针数组 指针数组模拟二维数组 数组名的理解 数组名是数组首元素的地址 例外&#xff1a; sizeof(数组名),sizeof中单独放数组名&#xff0c;这里的数组名表示整个数组&#xff0c;计算的…

从零开始手写mmo游戏从框架到爆炸(三)— 服务启动接口与网络事件监听器

上一章我们完成了netty服务启动的相关抽象&#xff08;https://blog.csdn.net/money9sun/article/details/136025471&#xff09;&#xff0c;这一章我们再新增一个全局的服务启动类&#xff0c;方便后续扩展。 服务启动 新增的两个类如下&#xff1a; 定义一个接口IServer …

6款超好用的IDEA插件,开发必备!

今天给大家介绍几款开发必备的IDEA插件&#xff1a; JRebel 热部署插件&#xff0c;让你在修改完代码后&#xff0c;不用再重新启动&#xff0c;很实用&#xff01;但是&#xff0c;不是免费的&#xff0c;需要大家继续发挥下自己的聪明才智才能happy的使用 Json Parser 厌倦…

Linux 多线程 | 线程的概念

线程的概念 线程是一个执行分支&#xff0c;执行粒度比进程更细&#xff0c;调度成本更低&#xff1b; 线程是进程内部的一个执行流&#xff1b; 线程是CPU调度的基本单位&#xff0c;进程是承担分配系统资源的基本实体。 之前我们学习过虚拟地址空间的知识&#xff0c;知道…