[一] C++入门

摘要:OOP(面向对象),namespace,cout and cin,缺省参数,函数重载,引用,内联函数,auto,范围 for,nullptr

20世纪80年代,计算机界提出了OOP(object oriented programming:面向对象)思想,支持面向对象的程序设计语言应运而生。C++是基于C语言而 产生的,它既可以进行C语言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行面向对象的程序设计。

A major design goal of C++ is to let programmers define their own types that are as easy to use as the built-in types.

——《C++ Primer》


1. 命名空间_namespace

namespace fantasy
{int a = 13;int l = 7;struct MyStructRB{int capacity;int size;}RB;
}int main()
{int sum = fantasy::a + fantasy::l;fantasy::RB.size = 0;fantasy::RB.capacity = 0;return 0;
}

导入_why

Question:全局变量与局部变量冲突时,优先哪个?     

#include<stdio.h>int num = 7;int main()
{int num = 13;printf("%d",num);return 0;
}

Answer:局部变量,因为查找的顺序是:先局部 ⇢ 再全局(output: 13

  • 为了解决变量名冲突的问题,命名空间应运而生

namespace_what

  • namespace:C++关键字
  • [name_of_namespace]:: 域作用限定符(::) ,左操作数为 name_of_namespace ,意为在该命名空间的区域内查找变量,如果左操作数为空,则表示在全局查找。 

Rules_use

  1. 命名空间的名称不应有空格,错误示例:

  2. 同名的命名空间会被合并

  3. 命名空间支持嵌套
    namespace fantasy
    {int a = 13;int l = 7;namespace RoundBottle{struct MyStructRB{int* array;int size;}RB;}
    }int main()
    {fantasy::RoundBottle::RB.size = 0;fantasy::RoundBottle::RB.array = nullptr;return 0;
    }

访问命名空间_declaration

  1. 指定命名空间访问
    std::cout << "Hello";
  2. 全局展开(日常练习中可以,项目中一般不会用全局展开):using namespace name_of_namespace;
    using namespace std;

2. C++ 输入&输出

  • stdC++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间
  • cout:输出流
  • cin:输入流
  • endl : 换行符(作用是换行并清空缓存区的数据
  • << 流插入运算符;>> 是流提取运算符;箭头方向可以理解为 “数据的流向 
#include <iostream>
using namespace std;int main()
{int num = 0;// 可以自动识别变量的类型cin >> num;//把数据输入到 num 这个变量中进行储存cout << num << endl;//将num中储存的数据输出(到屏幕)return 0;
}

3. 缺省参数

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

示例_example

  • 缺省参数分为全缺省部分缺省
//全缺省
int Add(int x = 1, int y = 2)
{return x + y;
}//部分缺省
int Sum(int x, int y, int z = 3)
{return x + y + z;
}

Rules_use

  1. 缺省参数不能跳跃,必须从左往右连续使用。错误示例
    #include<iostream>using namespace std;int Sum(int x = 1, int y, int z = 3)
    {return x + y + z;
    }int main()
    {int ret = Sum(1, 2);cout << ret << endl;return 0;
    }

    上述情况下,参数将无法确定传给谁,例如,参数“1”可能传给 x,也可能传给 y,因此这里出现了歧义,导致编译错误。同样的,上述代码也支持写成: ret = Sum( , 1, 2);

  2. 当函数的声明和定义分离时,缺省参数不能在声明和定义中同时出现,推荐在函数声明的时候给缺省参数(以下代码为错误示例
    //函数声明:
    int Add(int x = 1, int y = 2);//函数定义:
    int Add(int x = 1, int y = 2)
    {return x + y;
    }

应用场景_apply

(举例:栈的初始化)

C:

// 初始化栈 
void StackInit(Stack* ps)
{STDataType* tmp = (STDataType*)malloc(4 * sizeof(STDataType));if (!tmp){perror("malloc fail");exit(-1);}ps->_a = tmp;ps->_top = 0;ps->_capacity = 4;
}

CPP:

// 初始化栈 
void StackInit(Stack* ps, int initsize = 4)
{int* tmp = (int*)malloc(initsize * sizeof(int));if (!tmp){perror("malloc fail");exit(-1);}ps->_a = tmp;ps->_top = 0;ps->_capacity = initsize;
}
  •  知道栈中最多存100个数据:

    • StackInit(&stack, 100);
  •  不知道栈中最多存多少数据:

    • StackInit(&stack);

4. 函数重载

函数重载 → 在同一个命名空间,且函数名相同,参数不同,体现为三种方式:

  1. 类型不同 e.g.function(int p);   function(double p);
  2. 个数不同 e.g.function(int p);   function(int p1 , int p2)
  3. (类型的)顺序不同 e.g.function(int p , double p);    function(double p , int p );

  • Question:仅返回值不同,能构成函数重载吗?

Answer:❌不能!函数调用的时候并不能指明返回值,当两个函数只有返回值的类型不同时,在尝试调用函数时无法确认将要调用哪个函数,将发生编译错误!返回值类型是否相同与函数构成重载不相关

函数重载是如何实现的?

首先,我们需要了解代码的编译过程:(这里简单描述一下)

  1. 预处理:头文件展开(注意:头文件展开不同于“命名空间展开”,头文件展开是把头文件的内容复制一份,“命名空间展开”是授权,允许在该空间内进行查找),宏替换,去注释,条件编译    (test.cpp → test.i)
  2. 编译:检查语法,生成汇编代码(指令级代码)(test.i  → test.s)
  3. 汇编:汇编代码 → 二进制机器码  (test.s → test.o)
  4. 链接:合并多个 .cpp/.c 文件,生成可执行文件 (test.o →test.exe/test.out)

在链接的环节会生成符号表,类似这样:

符号表
nameaddress
functionxxxxxxxxxx
main

xxxxxxxxxx

…………

链接的时候会通过 name 找到 address,函数地址是一个跳转指令,如果函数没有定义只有声明就不会有地址,这将发生链接错误。

  • C语言:直接用函数名充当符号表中的name,如下图。
  • C++:对函数名进行修饰,不同平台下的修饰规则不同(从下图的链接错误中,可以看见vs2022平台下对函数名的修饰)。

sum.

  1. C++对函数名进行了修饰,不同平台下的修饰规则不同
  2. 自动识别函数参数的类型 (会不会使运行速度变慢?👉不会,可能影响编译速度,但不影响运行速度)

5. 引用_References

#include<iostream>using namespace std;int main()
{int v1 = 13;int& v2 = v1;v2 = 7;cout << v1 << endl; //output:7return 0;
}

References_what

  • 引用 —— 一块存储空间的 “别名”
  • Type& variable_reference = variable_entity Type 后跟“”表示引用,variable_referencevariable_entity 表示的是同一块存储空间的不同名称。注意:variable_entity 应该与 Type 相符合。

Rules_use 

  1. 定义时必须初始化

  2. 一个变量可以有多个引用

    int main()
    {int v1 = 13;int& v2 = v1;int& v3 = v1;int& v4 = v1;int* p = &a;int*& pb = p;return 0;
    }
  3. 引用在定义的时候必须初始化,因此只能引用一个实体,并且不能改变,否则会出现重定义

    int main()
    {int v1 = 13;int v2 = 7;int& v3 = v1;v3 = v2;//这是赋值,将v2的数据赋值给v3,同样的也是指v1int& v3 = v2;//错误:重定义!!return 0;
    }

常引用_const

  1. Type_const
    int main()
    {const int v = 13;int& v1 = 13;//errorconst int& v2 = 13;const int& v3 = v2;//correctreturn 0;
    }
    

    上述代码中,“13” 的 Typeconst int,是只读不可修改的常量,在语句 int& v1 = 13 中本是上发生了权限放大,导致错误。v1 的是 Typeint,是可读可修改的变量。权限可以平移、缩小,但不能放大。

  2. 隐式类型转化_Type Conversion

    int main()
    {int v_i = 0;double& v_d = v_i;//errordouble v_d2 = v_i;//correct,同样发生了类型转化,但这只是赋值语句return 0;
    }
    

    上述代码发生了隐式类型转化,int → double转化过程中会产生临时变量,临时变量具有属性!本质上来说这里仍发生了权限放大。

应用场景_apply

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

传引用的作用:①减少拷贝;②调用者可以修改该对象

1)做函数参数

传引用传参:输出型函数,形参的改变需要影响实参

void Swap(int& x, int& y)
{int tmp = x;x = y;y = tmp;
}int main()
{int x = 13, y = 7;Swap(x, y);cout << x << " " << y << endl;return 0;
}

2)做返回值:

传引用返回:函数的返回类型为一个引用

方式一:上图中的传引用返回可以直观的理解为下图中的代码 ⬇ ,_num 与 num 是同一块存储空间的不同名称,然后将这个空间中存储的数据赋值给变量 v 。warning:这样的行为是未定义的,因为 num 在出函数作用域时候被销毁,该存储空间被归还,再次访问这块空间会得到什么数据是不确定的。

方式二:“用引用来接收引用返回”,以下代码中,v 与 num 是同一块存储空间的不同名称,即表示同一块存储空间。

int& Count()
{int num = 0;++num;return num;
}int main()
{int& v = Count();cout << v << endl;//ouput:1cout << v << endl;//ouput:随机值return 0;
}

  • 注意:如果函数返回时,出了函数作用域,如果返回对象还在(还没还给系统),则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。

引用和指针的区别⭐

语法上有区别,但底层实现本质上是相同的。

  • 引用概念上定义一个变量的别名,指针存储一个变量地址。引用不开空间,指针开空间。
  • 引用在定义时必须初始化,指针没有要求
  • 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
  • 没有NULL引用,但有NULL指针
  • 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)
  • 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
  • 有多级指针,但是没有多级引用
  • 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
  • 引用比指针使用起来相对更安全
     

6. 内联函数_inline

当我们尝试实现一个可以进行加法运算的宏函数:以下 3 种写法都容易在使用 ADD宏函数的时候出现问题。

#define ADD(x,y) x+y
#define ADD(x,y) (x+y)
#define ADD(x,y) ((x)+(y));//better
#define ADD(x,y) ((x)+(y))

宏函数的优点:

  1. 没有严格的类型 (Type) 检查;
  2. 针对频繁调用的简单函数,无需建立栈帧,提高了效率。

宏函数的缺点:

  1. 容易出错,语法坑很多;
  2. 不能调试(预处理阶段将被直接替换);
  3. 没有类型 (Type) 的安全检查。

内联函数展开_what

基于此,C++选择使用内联函数:以 inline 修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数提升了程序运行的效率。

为了在调试的时候看到内联函数的展开我们需要关闭优化:步骤如下列图片

  • 调用函数:
  • 内联函数:

内联函数的特性

  1. inline 是一种以空间换时间的做法。
  2. inline 内联说明只是向编译器发送一个请求,最终是否展开由编译器决定。 
  3. inline 不建议声明和定义分离,分离会导致链接错误。因为内联函数会被直接展开,不进符号表 ,链接就会找不到。

补充:关于代码膨胀

对于内联函数,如果该函数定义包含 100 行代码,调用该函数 100 次,如果被内联展开,最终会被编译成 100*100 行指令,导致代码膨胀。对于非内联函数,如果该函数定义包含 100 行代码,调用该函数 100 次,最终会被编译成 100+100 行指令。因此,体量过大的、调用频繁的函数不建议内联展开。


7. auto_关键字

功能:自动识别类型

int main()
{int i = 0;auto v = i;auto v2 = 0;return 0;
}

Rules_use

  1. 不能用在函数参数类型声明上:❌void func(auto p){……}
  2. 不能声明数组:❌auto array[] = { 0 };

补充:查看变量的类型 —— typeid

int main()
{auto v = 1;const type_info& vInfo = typeid(v);cout << vInfo.name() << endl;//output:intreturn 0;
}

8. 范围 for

int main()
{int array[] = { 1, 2, 3, 4, 5 };cout << array << endl;for (auto& var : array){var *= 2;cout << &var << " " << var << endl;}for (auto num : array)cout << num << " ";//ouput:2 4 6 8 10//这里的var和num都是变量名,两者一不一样或取什么名字都是不影响的return 0;
}

注意:

  1. auto 一般和范围 for 搭配使用,但也可以指明具体的类型,for(int num : array) 类似的写法也是合法的,只是Type 应与 array 的类型相符合;
  2. 这里的 array 是能是数组名!错误示例如下,函数传参无法传递整个数组,这里实际上只是传过来数组首元素的地址。
    void func(int array[])
    {for (auto e : array)//error{……cout << e << endl;}
    }int main()
    {int array[] = { 1,2,3,4 };for (auto e : array[0])//also error{……}return 0;}
    

9.nullptr

简而言之,NULL在C++中出现了错误,所以引入  nullptr 

#define NULL 0 //error
#define NULL ((void*)0)

nullptr 使用注意:

  1. 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入 的。
  2. 在C++11中,sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同。
  3. 为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr。

END

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Hadoop RPC简介

数新网络-让每个人享受数据的价值https://www.datacyber.com/ 前 言 RPC&#xff08;Remote Procedure Call&#xff09;远程过程调用协议&#xff0c;一种通过网络从远程计算机上请求服务&#xff0c;而不需要了解底层网络技术的协议。RPC它假定某些协议的存在&#xff0c;例…

【计算机网络】计算机网络中的基本概念

文章目录 局域网LAN基于网线直连基于集线器组建基于交换机组建基于交换机和路由器组建 广域网WANIP地址端口号协议为什么要有协议知名协议的默认端口 五元组协议分层TCP/IP五层模型封装和分用 网络互连就是将多台计算机连接在一起&#xff0c;完成数据共享。数据共享本质是网络…

查询平均提速 700%,奇安信基于 Apache Doris 升级日志安全分析系统

本文导读&#xff1a; 数智时代的到来使网络安全成为了不可忽视的重要领域。奇安信作为一家领先的网络安全解决方案领军者&#xff0c;致力于为企业提供先进全面的网络安全保护&#xff0c;其日志分析系统在网络安全中发挥着关键作用&#xff0c;通过对运行日志数据的深入分析…

正则表达式续篇

位置锚定&#xff1a; ^:行首锚定&#xff0c;表示以什么为开头 例如&#xff1a; $:行尾锚定&#xff0c;表示以什么为结尾 例如&#xff1a; ^&#xff1a;匹配的是空行 例如&#xff1a; ^root$&#xff1a;匹配整行&#xff0c;而且整行只能有这一个字符串 实验&#x…

软考之软件工程基础理论知识

软件工程基础 软件开发方法 结构化方法 将整个系统的开发过程分为若干阶段&#xff0c;然后依次进行&#xff0c;前一阶段是后一阶段的工作依据按顺序完成。应用最广泛。特点是注重开发过程的整体性和全局性。缺点是开发周期长文档设计说明繁琐&#xff0c;工作效率低开发前要…

Golang Gin 接口返回 Excel 文件

文章目录 1.Web 页面导出数据到文件由后台实现还是前端实现&#xff1f;2.Golang Excel 库选型3.后台实现示例4.xlsx 库的问题5.小结参考文献 1.Web 页面导出数据到文件由后台实现还是前端实现&#xff1f; Web 页面导出表数据到 Excel&#xff08;或其他格式&#xff09;可以…

One-to-N N-to-One: Two Advanced Backdoor Attacks Against Deep Learning Models

One-to-N & N-to-One: Two Advanced Backdoor Attacks Against Deep Learning Models----《一对N和N对一&#xff1a;针对深度学习模型的两种高级后门攻击》 1对N&#xff1a; 通过控制同一后门的不同强度触发多个后门 N对1&#xff1a; 只有当所有N个后门都满足时才会触发…

测试为什么分白盒、黑盒、单元、集成测试?

对于想进入测试行业的小萌新&#xff0c;本文的诉求主要分为三块&#xff1a; 1、想知道分为这么多种测试的原因 2、解决各种概念问题 3、提供各种软件测试工具 安排&#xff01; 一、为什么测试的概念这么多 一个软件项目就好比一部复杂的汽车&#xff0c;有很多零件&#x…

Java作业二

一、使用方法编写求圆面积和周长的程序&#xff0c;运行时提示输入圆半径&#xff0c;然后输出计算结果。运行效果如下图所示&#xff1a; import java.util.Scanner;public class Test {public static void main(String[] args) {Scanner input new Scanner(System.in);Syste…

pycharm更改远程服务器地址

一、问题描述 在运行一些项目时&#xff0c;我们常需要在pycharm中连接远程服务器&#xff0c;但万一远程服务器的ip发生了变化&#xff0c;该如何修改呢&#xff1f;我们在file-settings-python interpreter中找到远程服务器&#xff0c;但是发现ip是灰色的&#xff0c;没有办…

最新Ai智能创作系统源码V3.0,AI绘画系统/支持GPT联网提问/支持Prompt应用+搭建部署教程

一、AI创作系统 SparkAi创作系统是基于OpenAI很火的ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如…

docker--基本操作

第 1 章 Docker基础 1.1 docker简介 在这一部分我们主要讲两个方面&#xff1a; docker是什么、docker特点 1.1.1 docker是什么 docker是什么&#xff1f; docker的中文解释是码头工人。 官方解释&#xff1a; Docker是一个开源的容器引擎&#xff0c;它基于LCX容器技术&…

设计模式之两阶段终止模式

文章目录 1. 简介 2. 常见思路3. 代码实战 1. 简介 两阶段终止模式&#xff08;Two-Phase Termination Pattern&#xff09;是一种软件设计模式&#xff0c;用于管理线程或进程的生命周期。它包括两个阶段&#xff1a;第一阶段是准备阶段&#xff0c;该阶段用于准备线程或进程…

C++:string类!

Cstring 是C中的字符串。 字符串对象是一种特殊类型的容器&#xff0c;专门设计来操作的字符序列。 不像传统的c-strings,只是在数组中的一个字符序列&#xff0c;我们称之为字符数组&#xff0c;而C字符串对象属于一个类&#xff0c;这个类有很多内置的特点&#xff0c;在操作…

某国产中间件企业:提升研发安全能力,助力数字化建设安全发展

​某国产中间件企业是我国中间件领导者&#xff0c;国内领先的大安全及行业信息化解决方案提供商&#xff0c;为各个行业领域近万家企业客户提供先进的中间件、信息安全及行业数字化产品、解决方案及服务支撑&#xff0c;致力于构建安全科学的数字世界&#xff0c;帮助客户实现…

进程空间管理:用户态和内核态

用户态虚拟空间里面有几类数据&#xff0c;例如代码、全局变量、堆、栈、内存映射区等。在 struct mm_struct 里面&#xff0c;有下面这些变量定义了这些区域的统计信息和位置。 unsigned long mmap_base; /* base of mmap area */ unsigned long total_vm; /* Total page…

人工智能-多层感知机

隐藏层 该模型通过单个仿射变换将我们的输入直接映射到输出&#xff0c;然后进行softmax操作。 如果我们的标签通过仿射变换后确实与我们的输入数据相关&#xff0c;那么这种方法确实足够了。 但是&#xff0c;仿射变换中的线性是一个很强的假设。 线性模型可能会出错 例如&…

【Spring】配置文件-properties和xml

文章目录 1. 前言2. properties配置文件3. xml配置文件4. 总结 1. 前言 在Spring中,配置文件有两种,properties配置文件和xml配置文件 properties配置文件&#xff0c;在Java编程中是一种常见的配置文件形式&#xff0c;文件后缀为“.properties”&#xff0c;属于文本文件。它…

十分钟设置免费海外远程桌面 | 使用Amazon Lightsail服务的免费套餐轻松搭建远程桌面

目录 使用Amazon Lightsail服务的免费套餐轻松搭建远程桌面 1. 启动Amazon Lightsail实例 2. 配置远程桌面 3. 启动远程桌面 4. 使用远程桌面 使用Amazon Lightsail服务的免费套餐轻松搭建远程桌面 前言 ①本教程将向您介绍如何使用Amazon Lightsail服务的免费套餐轻松搭…

知心早安问候语,愿你享受美好的时光,幸福快乐每一天

人生万里路&#xff0c;走好每一步&#xff0c;身体是本钱&#xff0c;平安是财富&#xff0c;开心就是护身符&#xff0c;健康才是摇钱树。新的一天&#xff0c;事事顺意&#xff01; 晨起福门开&#xff0c;快乐安康在&#xff0c;愉悦心态好&#xff0c;生活充满爱&#xf…