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

news2024/11/18 7:28:46

一、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_a
 
int& 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.coloradmin.cn/o/1882586.html

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

相关文章

潜水耳机哪个牌子好?用户精选,这四款潜水耳机质量上乘!

在这个快节奏的时代&#xff0c;人们越来越渴望在运动中也能享受到音乐的陪伴。潜水&#xff0c;作为一种独特的水下运动&#xff0c;自然也不例外。然而&#xff0c;并非所有的耳机都能承受水下的压力和环境&#xff0c;这就要求我们对潜水耳机有着更高的要求。作为一名资深的…

美团外卖搜索基于Elasticsearch的优化实践--图文解析

美团外卖搜索基于Elasticsearch的优化实践–图文解析 前言 美团在外卖搜索业务场景中大规模地使用了 Elasticsearch 作为底层检索引擎&#xff0c;随着业务量越来越大&#xff0c;检索速度变慢了&#xff0c;CPU快累趴了&#xff0c;所以要进行优化。经过检测&#xff0c;发现…

揭秘LLaMA 2:深度学习的未来,从原理到模型训练的全面剖析

引言 LLaMA&#xff08;Large Language Model for AI Assistance&#xff09;2 是 Meta&#xff08;原 Facebook&#xff09;开发的一个大型语言模型&#xff0c;旨在为各种自然语言处理任务提供强大的支持。它在前代基础上进行了改进&#xff0c;具有更好的性能和更广泛的应用…

LW-DETR: A Transformer Replacement to YOLO for Real-Time Detection

LW-DETR: A Transformer Replacement to YOLO for Real-Time Detection 论文链接&#xff1a;http://arxiv.org/abs/2406.03459 代码链接&#xff1a;https://github.com/Atten4Vis/LW-DETR 一、摘要 介绍了一种轻量级检测变换器LWDETR&#xff0c;它在实时物体检测方面超越…

Flutter集成高德导航SDK(Android篇)(JAVA语法)

先上flutter doctor&#xff1a; flutter sdk版本为&#xff1a;3.19.4 引入依赖&#xff1a; 在app的build.gradle下&#xff0c;添加如下依赖&#xff1a; implementation com.amap.api:navi-3dmap:10.0.700_3dmap10.0.700navi-3dmap里面包含了定位功能&#xff0c;地图功能…

技术反诈指南丨央视报了!基于“AI换脸”的新型电信网络诈骗猖獗

目录 利用“AI换脸”技术的诈骗 技术上防范新型电信网络诈骗 内蒙古鄂尔多斯市居民李女士近日遭遇了一起新型电信网络诈骗案。诈骗团伙利用“AI换脸”技术&#xff0c;合成了与李女士老同学相似的视频通话&#xff0c;以此作为诈骗的关键手段&#xff0c;成功骗取李女士信任。 …

[数据质量]手动实现 阿里云DataWorks 的数据质量监控告警功能

目录 手动实现 DataWorks 的数据质量监控告警功能1. 简介:2. 数据表准备2.1 tmp_monitor_tbl_info (数据监控信息表)2.2 tmp_monitor_rule_info (数据质量监控规则表)2.3 tmp_monitor_tbl_info_log_di (数据监控信息记录表) 3. 程序开发3.1 数据检查程序3.2 告警信息推送程序3.…

Navcat Premium17破解安装及数据库连接教程

一、前言 Navicat Premium 是一套数据库开发工具&#xff0c;是一个可多重连接数据库的管理工具。Navicat Premium让你从单一应用程序中同时连接 MySQL、MariaDB、MongoDB、SQL Server、Oracle、PostgreSQL 和 SQLite 数据库。目前17已经支持了很久都没有支持的Redis数据库了。…

大数据之Zookeeper部署

文章目录 集群规划环境准备集群部署参考资料 集群规划 确定使用Hadoop101、hadoop102和hadoop103三台服务器来构建Zookeeper集群。 hadoop101hadoop102hadoop103zookeeperzookeeperzookeeper 环境准备 安装zookeeper前需要确保下面的环境配置成功&#xff0c;具体可以参考大…

七一建党节|热烈庆祝中国共产党成立103周年!

时光荏苒&#xff0c;岁月如梭。 在这热情似火的夏日&#xff0c; 我们迎来了中国共产党成立103周年的重要时刻。 这是一个值得全体中华儿女共同铭记和庆祝的日子&#xff0c; 也是激励我们不断前进的重要时刻。 103年&#xff0c; 风雨兼程&#xff0c;砥砺前行。 从嘉兴…

五种肉苁蓉属植物叶绿体基因组-文献精读25

Structural mutations of small single copy (SSC) region in the plastid genomes of five Cistanche species and inter-species identification 五种肉苁蓉属植物叶绿体基因组中小单拷贝 (SSC) 区域的结构突变及物种间鉴定 摘要 背景 肉苁蓉属是列当科的重要属类&#xf…

小型气象站:便携、高效的气象监测新选择

在气象监测领域&#xff0c;一款小巧而功能全面的设备正逐渐受到广泛关注——那就是小型气象站。它不仅体积小巧、重量轻&#xff0c;而且采用了众多先进技术&#xff0c;使其在气象数据的采集、传输和分析中展现出强大的能力。 小型气象站之所以备受青睐&#xff0c;首先得益于…

error LNK2019: 无法解析的外部符号 _SDL_main,该符号在函数 _main_getcmdline 中被引用

VC MFC情况下出现此问题&#xff0c; 网上搜索了很多文章无法解决。 error LNK2019: 无法解析的外部符号 _SDL_main&#xff0c;该符号在函数 _main_utf8 中被引用_sdl2main.lib出现无法解析的外部符号-CSDN博客 字符集必须设置为&#xff1a;

交叉编译 tcpdump libpcap

文章目录 交叉编译 tcpdump & libpcap概述源码下载交叉编译 libpcap交叉编译 tcpdump 交叉编译 tcpdump & libpcap 概述 tcpdump 是一个强大的命令行包分析器&#xff0c;libpcap 是一个可移植的用于网络流量捕获的 C/C 库。tcpdump 依赖于 libpcap 库&#xff0c;同…

Jenkins接口自动化项目的工程创建

jenkins的下载安装 jenkins下载的官网地址 https://www.jenkins.io/download/ java环境变量的配置下载 jenkins是用java语言编写的所以要配置java环境 需要安装java的JDK 推荐安装JDK17(https://blog.csdn.net/wochunyang/article/details/138520209) JDK17的下载地址 ht…

红黑树模拟

1.红黑树概念 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但每个节点上增加了一个存储位表示结点的颜色&#xff0c;可以是RED或BLACK。通过任何一条根到叶子节点的途径上各个节点的着色方式的限制&#xff0c;红黑树确保没有一条路径会超过其他路径的二倍&#xff0c;因…

基于Cisco模拟器的组网实验

课程目的 综合运用所学的网络原理、网络规划和网络集成等知识理论&#xff0c;按照下图所示&#xff0c;完成网络的规划、集成与配置&#xff0c;并利用ACL实现对网络的管理。 实验内容 连接并配置路由器&#xff0c;配置路由协议&#xff08;RIP或OSPF&#xff09;&#xf…

[Microsoft Office]Word设置页码从第二页开始为1

目录 第一步&#xff1a;设置页码格式 第二步&#xff1a;设置“起始页码”为0 第三步&#xff1a;双击页码&#xff0c;出现“页脚”提示 第四步&#xff1a;选中“首页不同” 第一步&#xff1a;设置页码格式 第二步&#xff1a;设置“起始页码”为0 第三步&#xff1a;双…

现在电气真的比不过计算机吗 ?

电气工程和计算机科学在今天的科技和工业领域中各有其重要性和发展空间&#xff0c;并不存在简单的比较谁“比不过”谁的情况。我收集制作一份plc学习包&#xff0c;对于新手而言简直不要太棒&#xff0c;里面包括了新手各个时期的学习方向&#xff0c;包括了编程教学&#xff…

【爱上C++】详解string类2:模拟实现、深浅拷贝

在上一篇文章中我们介绍了string类的基本使用&#xff0c;本篇文章我们将讲解string类一些常用的模拟实现&#xff0c;其中有很多细小的知识点值得我们深入学习。Let’s go&#xff01; 文章目录 类声明默认成员函数构造函数析构函数拷贝构造函数深浅拷贝问题传统写法现代写法…