C++(第一天-----命名空间和引用)

一、C/C++的区别

1、与C相比
  c语言面向过程,c++面向对象。
  c++能够对函数进行重载,可使同名的函数功能变得更加强大。
  c++引入了名字空间,可以使定义的变量名更多。
  c++可以使用引用传参,引用传参比起指针传参更加快,指针传参还需要传送,而引用传参不需要传送参数,就能使函数共用一个变量。
  c++使用了类,能够继承,继承使得定义相似的类时能够直接从上一层得到一些方法或变量来进行直接使用。
  c++相比C语言功能强大的同时,也带来了更复杂多样的语法,这对于初学者来说是一个大的难点,这也使得c++在编程和学习上的难度提高了,并且c++的效率仍然不如C语言,c语言适合底层开发,c++适合c/s的软件开发. c/s — client /server。
2、C的扩展
C++是在C语言的基础上扩展而来,所以C++ 完全兼容C语言,可以在C++程序中写C语言的代码。

二、在c++中使用c语言库函数

extern "C"{//标准C库函数的头文件#include<stdio.h>//自定义的第三方C库头文件//也就是你使用的C编译器编译好的库对应的头文件#include "add.h"
}

例子:编译一个动态库 libadd.so

gcc -fpic -shared add.c  -o  libadd.so 

extern "C"的主要作用就是为了能够正确实现C++代码调用其他C语言代码。加上extern "C"后,会指示编译器这部分代码按C语言的方式进行编译,而不是C++的。

c++标准的头文件不带.h

三、命名/名字/名称空间 namespace

1、问题的引入
探讨:在实际的系统开发中,所有的开发工作,通常都不会仅由一个人来开发完成,不同的人只负责自己功能模块,他们在设计时,比如声明变量,通常情况下,不会考虑其他人是否已使用该变量名,在模块功能测试时,相互之间是独立的,完全没有问题,当系统功能合成 时,不可避免地会出现变量或函数的命名冲突,因为变量或函数重名而导致的问题将会造成一定的混乱。所以如何在同一个.cpp文件中定义相同变量名的两个全局变量呢

#include<iostream>int val = 200;
int val = 300;int main()
{return 0;
}

现象:编译会报错
解决方法:使用命名空间区分这两个全局变量
在这里插入图片描述
2、概念
其实命名空间就是类似一个黑盒子
3、作用
防止名字冲突
4、格式

namespace 命名空间名字
{//声明定义变量//声明定义函数//定义结构体/共用体/枚举 数据类型//声明类  定义对象
}

5、使用命名空间中的成员
1)using编译指令( 引进整个命名空间) —将这个盒子全部打开

 using namespace 命名空间名字;

2)using声明使特定的标识符可用(引进命名空间的某个成员) —将这个盒子中某个成员的位置打开

using 命名空间名字::成员名;

3)调用的时候指定是哪一个命名空间下的成员

cout<<命名空间名字::成员名

6、实例

#include<iostream>using namespace std;//使用名称空间LcdSpace   -501老王
namespace LcdSpace{int x = 10;int y = 20;typedef struct{int data;}Data_t;enum {LCD_COLOR_RED,LCD_COLOR_GREEN};int lcd_init(){return 0;}}; 
//使用名称空间TouchSpace -502老王
namespace TouchSpace{int x = 100;int y = 200;
};//外部的全局变量   --老外
//int x = 1000;
//int y = 2000;//2)使用using声明的方式去引入名字空间中的某个成员
//把这个TouchSpace黑盒子 打开一个角落,正好把某个成员放出来
//格式:using 命名空间名字::成员名;
//using  TouchSpace::x;void test01()
{using namespace LcdSpace;cout<<"x:"<<x<<" y:"<<y<<endl;
}int main()
{//3)使用using编译指令的方式 打开整个名字空间 using namespace TouchSpace;//如何使用名字空间里面的成员//1)使用 作用域限定符:: 去指定//格式:  名字空间的名字::成员变量名std::cout<<TouchSpace::x<<" "<<TouchSpace::y<<std::endl;std::cout<<x<<" "<<y<<std::endl;std::cout<<LcdSpace::x<<" "<<LcdSpace::y<<std::endl;LcdSpace::Data_t data;LcdSpace::lcd_init();//我们有时候为了强调该变量的全局特性,可以在前面加上::修饰cout<<x<<" "<<y<<endl;test01();return 0;
}

7、命名空间的嵌套

namespace myspace{int x=10;int y=20;namespace spaceA{int a=100;void setValue(int data){a = data;}void printValue(){std::cout<<"a:"<<a<<std::endl;}}
}
使用:
myspace::spaceA::printValue();

8、同名命名空间
命名空间可以分开定义,也就是说,你在定义一个命名空间之后,如果后面想要在这个命名空间里面再次添加某些数据成员或者函数成员,可以再次接着定义。

namespace myspace{int x=10;int y=20;
}
namespace myspace{int a=100;int b=200;void print(){std::cout<<"x:"<<x<<" y:"<<y<<std::endl;}
}

9、匿名命名空间

namespace {int data=123;
}

可以在本文件中直接使用data, 限制空间中的成员只能在本文件中使用,类似c语言中的static修饰

10、全局作用域
全局作用域是从C语言就开始有的一种作用域,在C++中,有时为了强调某符号的全局特性,或为了避免与导入的名字空间中的重名符号冲突,会在使用全局符号的时候加上 作用域解析符

int global = 100;
int main()
{int global = 200;// 重名的标识符,外层的作用域会被内层的掩盖cout <<   global << endl; // 输出200// 使用双冒号引用全局作用域中的标识符cout << ::global << endl; // 输出100
}

1.全局作用域的名字空间是匿名的,引用全局作用域符号只需加 :: 即可。
2.名字空间的本质就是作用域,遵守C语言关于作用域的基本原则,如内层作用域重名符号会掩盖外层作用域的重名符号。

四、引用

1、问题的引入

//值传递
int swap1(int a,int b)
{a = a+b;b = a-b;a = a-b;    
}
//地址传递
int swap2(int *pa,int *pb)
{int temp = *pa;*pa = *pb;*pb = temp;
}
int  main()
{int aa = 100;int bb = 200;swap1(aa,bb);//值传递swap2(&aa,&bb);//地址传递
}

问题:值传递书写方式简单,但是不能修改变量所在内存空间的数据;地址传递能够修改变量所在内存空间的数据,但是需要复杂的解引用写法,而且使用过程中可能出现问题(空指针,不合法内存),导致程序不安全。
有没有一种方法:集中两者的优点呢,也就是说,既能够书写简单,同时也能修改内存空间的数据,提高程序的安全性!
解决方法:使用C++中的引用。
2、概念
引用就是一个变量或者是常量的别名,对引用的操作与对变量直接操作完全一样。引用是一种关系型声明的类型,说明它跟别的变量的关系,它所声明的变量不占内存空间,通俗来讲,是已有变量的别名,来说明跟已有变量的关系,所以引用变量的类型要跟已有变量的类型保持一致。
在这里插入图片描述
3.定义格式
以前的指针:数据类型 * 指针名 = &变量
现在的引用:数据类型 & 引用名 = 变量(数据类型必须与变量类型一致,而且必须要初始化)

int a = 100;
//给变量a起一个别名(定义引用)
//int 表示引用变量的数据类型,ra表示给变量a起的小名字就叫做ra
int &ra = a;
char *str = "hello";
char*(&rs) = str;//给指针变量str定义一个引用rs//给常量10起一个别名,给常量起一个别名必须在定义引用的时候加const 修饰
const int &rval = 10;

5.引用特点

  • &在定义的时候不是取地址运算符,而是起标识作用,表示给某个变量或者常量起一个别名,所以引用不是变量。
  • 在定义引用的时候,数据类型指的是 目标变量或者常量的数据类型。
  • 定义引用的时候,必须同时对其进行初始化。
  • 引用定义完毕后,相当于目标变量有两个名称,也就是目标原变量名和引用名,直接使用引用名就相当于直接操作该目标变量对应的内存空间。
  • 引用定义完毕后,不能 再把该引用名作为其他变量名的别名
  • 引用本身不占存储单元,仅仅是作为变量的别名。对引用求地址,就是对目标变量求地址。&ra与&a相等。
  • 不能建立引用的数组。因为数组是一个由若干个元素所组成的集合,所以无法建立一个由引用组成的集合,但是可以建立数组的引用。
const int &arr[3]={1,2,3}; 引用的数组----错误    [] 优先级 大于 &
int n[3] = {2, 4, 6};
int (&rn)[3] = n;     //数组的引用
  • 如果引用的对象是常量,那么引用必须用const修饰
int a = 100;
int b = 200;
//给变量a起一个别名(定义引用)
int &ra = a;
ra = b;//将变量b的值赋值给变量a所在的内存空间
cout<<"a:"<<a<<endl;
//引用取地址与变量取地址相等
cout<<"&a:"<<&a<<" &ra:"<<&ra<<endl;
//给常量10起一个别名
const int &rval = 10;

6.引用与常量

  • 将一个引用设置为常量后,不能通过该引用修改数据,但仍可通过被引用的变量来改变
int a = 100;
const int & b = a;//b和a是同一内存,但不能直接修改b
b = 1000;//错误
a = 1000;//正确

被引用的数据是常量,引用本身也必须是常量:

const int a = 100;
const int &b = a;//OK
int &b = a;//error
int &ra = 10;//error
const &ra = 10;//OK

7.引用的应用

  • 引用作为参数(值, 地址, 引用)
    引用的一个重要作用就是作为函数的参数。C语言阶段 如果在某个函数中想要改变另一个函数的变量,则需要进行地址传递,现在C++阶段又新增了一个引用传递,同样也能在一个函数中修改另一个函数的变量。
int func(int &ra,int &rb)
{ra = ra + rb;rb = ra - rb;ra = ra - rb;
}
//如果仅仅是访问变量的数据而不做修改,可以设置为常引用,达到引用的安全性
//常引用不能通过引用修改目标变量的值,
int print(const int &ra,const int &rb)
{cout<<ra<<" "<<rb<<endl;
}
int main()
{int a = 10;int b = 20;func(a,b); // func(10,20); 错误 ,因为该函数定义的参数不是常引用print(a,b); 
}
  • 引用作为函数返回值
    格式:
返回值数据类型 &函数名(形参列表及类型说明)
{

特点:
a. 以引用的形式返回函数值,定义函数时需要在函数名前加&
b. 用引用返回一个函数值的最大好处是,在内存中不产生被返回值 的副本。

#include <iostream>
using namespace std;int g_a; // 定义全局变量g_aint& test() {g_a = 168;return g_a;
}int main()
{//左值变量i 是直接从变量g_a中拷贝int i = test();cout << i << endl; return 0;
}

c. 不能返回局部变量的引用 ,因为局部变量在函数调用结束之后内存空间就被释放了

char*& initMem(int size)
{char *p = new char[size];return p;
}
int main()
{//会发生段错误,不能返回局部变量的引用char*(&p) = initMem(1024);strcpy(p,"hello");
}
正确写法:把initMem函数的p指针改为全局变量或者静态变量
char*& initMem(int size)
{static char *p = new char[size];return p;
}

d. 如果一个函数的返回值是一个引用,那么函数可以调用可以作为=的左值

test() = 100;
int val=100;int& getData()
{return val;
}
int main()
{getData() = 200;cout<<"val:"<<val<<endl;}

8.总结
引用传递的性质像指针传递,书写形式像值传递
如果只需要借用一下别名,就没必要要用指针
练习1:求下面的结果

#include <iostream> 
using namespace std; 
int f(int i){ return ++i; } 
int& g(int &i){ return ++i; } 
int h(int i){ return ++i; } 
int main() 
{ int a = 0, b = 0, c = 0; a += f(g(a)); b += g(g(b)); c += f(h(c)); cout << "a=" << a << ",b=" << b << ",c=" << c << endl; return 0;  
}

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

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

相关文章

企业化运维(5)_mysql数据库

###1.源码编译mysql### 对压缩包进行解压&#xff0c;并对mysql进行源码编译&#xff0c;其中需要下载依赖才能编译成功。 官网&#xff1a; www.mysql.com解压并进入目录 [rootserver1 ~]# tar xf mysql-boost-5.7.40.tar.gz [rootserver1 ~]# cd mysql-5.7.40/安装依赖性…

初识Java(复习版)

一. 什么是Java Java是一种面向对象的编程语言&#xff0c;和C语言有所不同&#xff0c;C语言是一门面向过程的语言。偏底层实现&#xff0c;比较注重底层的逻辑实现。不能一味的说某一种语言特别好&#xff0c;每一种语言都是在特定的情况下有自己的优势。 二.Java语言发展史…

昇思25天学习打卡营第2天|yulang

今天主要了解快速入门&#xff0c;主要包含了处理数据集、网络构建、模型训练、保存模型和加载模型&#xff0c;这些对于不是算法工程师理解起来可能稍微有一点的难度&#xff0c;学习起来有点枯燥&#xff0c;期待后续实战部分能完成一些独立的比较有意思的项目。

鸿蒙项目实战-月木学途:2.自定义底部导航

效果预览 Tabs组件简介 Tabs组件的页面组成包含两个部分&#xff0c;分别是TabContent和TabBar。TabContent是内容页&#xff0c;TabBar是导航页签栏&#xff0c;页面结构如下图所示&#xff0c;根据不同的导航类型&#xff0c;布局会有区别&#xff0c;可以分为底部导航、顶部…

8617 阶乘数字和

这是一个关于计算阶乘结果所有位上的数字之和的问题。我们可以通过以下步骤来解决这个问题&#xff1a; 1. 首先&#xff0c;我们需要一个函数来计算阶乘。由于n的范围可以达到50&#xff0c;阶乘的结果可能非常大&#xff0c;所以我们需要使用一个可以处理大整数的数据类型&a…

怎么找到DNS服务器的地址?

所有域都注册到域名名称服务器&#xff08;DNS&#xff09;点&#xff0c;以解析域名应指向的IP地址。此查找类似于在查找个人名称并查找其电话号码时的电话簿如何运行。如果DNS服务器设置错误或指向错误的名称服务器&#xff0c;则域可能无法加载相应的网页。 如何查找当前的…

(3)Java 8 实战第二版——使用流和Lambda进行高效编程

集合工厂 List<String> friends Arrays.asList("Raphael", "Olivia"); friends.set(0, "Richard"); friends.add("Thibaut"); ←---- 抛出一个UnsupportedModificationException异常通过工厂方法创建的Collection的底层…

CrossViT:用于图像分类的交叉注意多尺度Vision Transformer

提出了一种双支路Transformer来组合不同大小的图像补丁(即变压器中的令牌)以产生更强的图像特征。方法处理具有不同计算复杂度的两个独立分支的小补丁和大补丁令牌,然后这些令牌纯粹通过注意多次融合以相互补充。此外,为了减少计算量,开发了一个简单而有效的基于交叉关注的令…

C++基础编程100题-020 OpenJudge-1.3-20 计算2的幂

更多资源请关注纽扣编程微信公众号 http://noi.openjudge.cn/ch0103/20/ 描述 给定非负整数n&#xff0c;求2n。 输入 一个整数n。0 < n < 31。 输出 一个整数&#xff0c;即2的n次方。 样例输入 3样例输出 8参考程序-1 #include<bits/stdc.h> using nam…

JavaScript高级程序设计(第四版)--学习记录之对象、类和面向对象编程(中)

创建对象方式 工厂模式&#xff1a;用于抽象创建特定对象的过程。可以解决创建多个类似对象的问题&#xff0c;但没有解决对象标识问题。&#xff08;即新创建的对象是什么类型&#xff09; function createPerson(name, age, job) { let o new Object(); o.name name; o.age…

Android:移动垃圾软件

讲解政策相关,最近升级AI扫荡系统和证书防高风险,回复按留言时间来排,请耐心等待 移动垃圾软件 官方政策公告行为透明、信息披露清晰保护用户数据不要损害移动体验软件准则反垃圾软件政策Google API 服务用户数据政策官方政策公告 ​ 在 Google,我们相信,如果我们关注用户…

Retrofit源码阅读

动态代理在 Android 中的应用&#xff1a;Retrofit 源码解析 在之前的文章 《Andriod 网络框架 OkHttp 源码解析》 中我们分析了 OkHttp 的源代码。现在我们就来分析一下 OkHttp 的兄弟框架 Retrofit。关于 Retrofit 的注解的使用&#xff0c;可以参考其官方文档&#xff1a;h…

控制台厂商配额查询

概述 厂商推送限制 每个厂商通道都有对应的厂商配额和 QPS 限制&#xff0c;当请求超过限制且已配置厂商回执时&#xff0c;MobPush会采取以下措施&#xff1a; 当开发者推送请求超过厂商配额时&#xff0c;MobPush将通过自有通道进行消息下发。当开发者推送请求超过厂商 QPS…

Spark on k8s 源码解析执行流程

Spark on k8s 源码解析执行流程 1.通过spark-submit脚本提交spark程序 在spark-submit脚本里面执行了SparkSubmit类的main方法 2.运行SparkSubmit类的main方法&#xff0c;解析spark参数&#xff0c;调用submit方法 3.在submit方法里调用doRunMain方法&#xff0c;最终调用r…

算法-位图与底层运算逻辑

文章目录 1. 位图的理论基础2. 完整版位图实现3. 底层的运算逻辑-位运算 1. 位图的理论基础 首先我们要理解什么是位图, 位图的一些作用是什么 位图法就是bitmap的缩写。所谓bitmap&#xff0c;就是用每一位来存放某种状态&#xff0c;适用于大规模数据&#xff0c;但数据状态又…

Python+Pytest+Allure+Yaml+Pymysql+Jenkins+GitLab接口自动化测试框架详解

PythonPytestAllureYaml接口自动化测试框架详解 编撰人&#xff1a;CesareCheung 更新时间&#xff1a;2024.06.20 一、技术栈 PythonPytestAllureYamlJenkinsGitLab 版本要求&#xff1a;Python3.7.0,Pytest7.4.4,Allure2.18.1,PyYaml6.0 二、环境配置 安装python3.7&…

ROS2 RQT

1. RQT是什么 RQT是一个GUI框架&#xff0c;通过插件的方式实现了各种各样的界面工具。 强行解读下&#xff1a;RQT就像插座&#xff0c;任何电器只要符合插座的型号就可以插上去工作。 2.选择插件 这里我们可以选择现有的几个RQT插件来试一试&#xff0c;可以看到和话题、参…

金蝶云星空字段之间连续触发值更新

文章目录 金蝶云星空字段之间连续触发值更新场景说明具体需求&#xff1a;解决方案 金蝶云星空字段之间连续触发值更新 场景说明 字段A配置了字段B的计算公式&#xff0c;字段B配置了自动C的计算公式&#xff0c;修改A的时候&#xff0c;触发了B的重算&#xff0c;但是C触发不…

XMind2TestCase:高效测试用例设计工具

XMind2TestCase&#xff1a;高效测试用例设计工具 引言传统测试用例设计的问题1. Excel表格的局限性2. 传统测试管理工具的不足3. 自研测试管理工具的挑战 思维导图在测试用例设计中的应用思维导图的优势思维导图的挑战 简介安装使用方式命令行调用使用Web界面 使用示例XMind文…

广州自闭症机构哪家好

在广州&#xff0c;众多的自闭症康复机构中&#xff0c;星贝育园自闭症儿童康复学校以其独特的优势脱颖而出。 一、专业的师资团队 我们拥有一支经验丰富、专业素养极高的师资队伍。每位老师都经过严格的专业培训&#xff0c;深入了解自闭症儿童的特点和需求。他们不仅…