《C++笔记 第一部分 C++语言篇》第3章 内存模型及名字空间

2024-08-30 13:08

本文主要是介绍《C++笔记 第一部分 C++语言篇》第3章 内存模型及名字空间,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

3.1作用域

 作用域(scope)描述了一个名字在文件(编译单元)的多大范围内可见。

 C++支持三种形式的域:

  •  局部域(local scope)
    局部域是包含在函数定义或者函数块中的程序文本部分。
  •  名字空间域(namespace scope)
    名字空间域是不包含在函数声明函数定义或者类定义内的程序文本部分
    程序的最外层的名字空间域被称作全局域(global scope),或全局名字空间域(global namespace scope)
    对象函数类型以及模板都可以在全局域中定义
    可以利用名字空间定义namespace definition 来定义用户声明的user-declared 的名字空间。每个用户声明的名字空间都是一个不同的域,它们都与全局域不同,与全局域相同的是用户声明的名字空间可以包含对象函数类型和模板的声明与定义,以及被嵌套其内的用户声明的名字空间。
  •  类域(class scope)
    每个类定义都引入了一个独立的类域

 变量的作用域

  •  局部变量的作用域为局部,仅能在代码块内可见
  •  "{}"就是代码块的作用域,函数、switch、for、while,等等
  •  全局变量的作用域为全局的,在定义处开始直到文件尾可见
  •  自动变量的作用域是局部的,静态变量的作用域要看其定义位置
  •  函数原型作用域
    在函数原型声明时候,在"()“内声明的参数列表中的变量,仅能在”()"内可见。正因为如此,所以函数声明时,有无形参,形参是什么都不重要。
  •  名字空间作用域
    在指定名字空间中定义的变量,在整个名字空间中可见。
  •  类作用域
    类中声明的变量,在整个类内部可见,不管是什么权限的变量。

 函数的作用域
可以是整个类,也可以是整个名字空间,但不能是局部的。

3.2链接性及存储性

链接性(linkage)描述了名称如何在各个单元中的共享。
外部链接:是指名称可以在文件间共享
内部链接:名称仅仅能在一个文件中的函数共享
变量的链接性及存储性(下表):

表1

在这里插入图片描述
 变量的说明限定符
auto(C++11中没有)、register、static、extern、thread_local(C++11新增)、mutable、const、volatile

 函数的链接性及存储性
函数的存储持续性为静态的
默认的情况下,函数的链接性为外部的
要引用函数,可以加extern说明限定符
加static说明限定符的函数,链接性为内部的;如果和外部的函数重名,则静态的函数替换之。
非内联函数受单定义规则限制,但是内联函数则不然。C++运行内联函数的定义放在头文件内。不过一个内联函数所有的定义必须相同。

 语言链接性
对于函数或变量而言,只要有链接性,则每种编程语言,都有自己的规则来处理它们的名字。这个就是语言的链接性。
如果C语言编写的函数需要被C++代码使用到,就要注意到语言的链接性。

extern "C" void spiff(int);//use C protocol for name look-up
extern void spoff(int);//use C++ protocol for name look-up
extern "C++"void spaff(int);//use C++ protocol for name look-up

3.3动态内存

变量的5种存储方案(线程内存除外)中仅仅描述了自动存储和静态存储,并没有说明动态存储的情况。C中malloc/free分配管理的堆区就是动态内存,C++中则引入了运算符new/delete来分配内存。

运算符new可以动态创建对象,创建对象后会返回对象的地址。如果内存不足导致车无法成功创建对象,则归返回一个空指针。
动态创建的对象要用“delete对象指针”才能销毁对象;
运算符符new和new[]调用的函数如下:

void *operator new (std :: size_t);//used by new
void *operator new[] (std :: size_t);//used by new[]

运算符符delete和delete[]调用的函数如下:

void operator delete(void *);
void operator delete[] (void *);

定位new运算符:

int *p2 = new(buffer) int;
invokes new(sizeof(int),buffer );

例子:用Box类创建对象

Box *pt1;
pt1 = new Box;//创建对象
delete pt1;//销毁对象
Box *pt1= new Box(32);//创建对象
Box *pt;
pt = new Box;//创建对象
if(pt != NULL)
{delete pt;pt = NULL; 
}

3.4声明区与作用域

 C++标准的名字空间属性
声明区:可以进行声明的区域
潜在的作用域:变量潜在的作用域,从声明点,到声明区结尾

 变量并非在潜在的作用域内都可见,只要存在嵌套声明区,且和内部声明区的变量重名,则会被内部声明区的变量隐藏

 每个声明区都可以声明名称,且相互独立。也就意味着,即使不同声明区的出现了同名,也不会发送冲突。

在这里插入图片描述

3.5引用

引用是变量的别名,,不会再开辟空间。引用在实计开发中,只使用于函数的形式参数。比喻:引用是一种受限指针。引用能做的事指针都能做,而指针能做事引用不一定能用。引用的底层实现多数编译器也是指针.

#include <iostream>
using namespace std;void f1() {int a = 20;int &b = a;//创建引用类型变量时,要立刻 "赋值"int c = 100;b = c;cout<<b<<endl;//100cout<<a<<endl;//100cout<<&a<<endl;// 0x7fffcaa6ca10cout<<&b<<endl;// 0x7fffcaa6ca10
}void f2(int *p) {*p = 21;
}void f3(int &r) {//int &r = ager = 22; //age=22
}int main() {
f1();int age = 20;//调用函数,让age的值改变为21f2(&age);cout<<"age="<<age<<endl;//age=21//调用函数,让age的值改变为22; 但是不能使用指针f3(age);cout<<"age="<<age<<endl;//age=22return 0;
}

结果如下所示:

在这里插入图片描述

3.6名字空间

 命名声明区
namespace 名称{
//声明区
}

 使用名称空间

 声明的话,则直接使用
using 名称::变量
using 名称::函数名

 不声明的话
名称::变量或函数名

参考代码

fs.cpp文件

#include "fs.h"namespace fs1
{namespace one204{void test(){}}void show1() {}void show() {}void Stu::study(){}}namespace fs2
{void show2(){}void show(){}void Stu::sleep(){}
}

fs.h文件

#ifndef FS_H_
#define FS_H_namespace fs1
{namespace one204{void test();}void show1();void show();class Stu{public:void study();};
}namespace fs2
{void show2();void show();class Stu{public:void sleep();};
}
#endif /* FS_H_ */

main.cpp文件

/********************************************************************************* @file    		main.cpp* @author  		BruceOu* @version 		V1.0* @date    		2019.03.03* @brief          命名空间*******************************************************************************/
/**Includes*********************************************************************/
#include <iostream>
#include "fs.h"/**namespace********************************************************************/
//using namespace std;
using namespace fs1::one204;
using namespace fs1;
using namespace fs2;/*** @brief     主函数* @param     argcargv* @retval    None*/
int main(int argc, char *argv[])
{std::cout<<"fsdfsd"<<std::endl;fs1::one204::test();fs1::one204::test();fs1::show1();fs1::show();fs2::show();fs1::Stu stu;stu.study();fs2::Stu stu2;stu2.sleep();show2();return 0;
}

这篇关于《C++笔记 第一部分 C++语言篇》第3章 内存模型及名字空间的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1120910

相关文章

Java内存泄漏问题的排查、优化与最佳实践

《Java内存泄漏问题的排查、优化与最佳实践》在Java开发中,内存泄漏是一个常见且令人头疼的问题,内存泄漏指的是程序在运行过程中,已经不再使用的对象没有被及时释放,从而导致内存占用不断增加,最终... 目录引言1. 什么是内存泄漏?常见的内存泄漏情况2. 如何排查 Java 中的内存泄漏?2.1 使用 J

Golang的CSP模型简介(最新推荐)

《Golang的CSP模型简介(最新推荐)》Golang采用了CSP(CommunicatingSequentialProcesses,通信顺序进程)并发模型,通过goroutine和channe... 目录前言一、介绍1. 什么是 CSP 模型2. Goroutine3. Channel4. Channe

使用SQL语言查询多个Excel表格的操作方法

《使用SQL语言查询多个Excel表格的操作方法》本文介绍了如何使用SQL语言查询多个Excel表格,通过将所有Excel表格放入一个.xlsx文件中,并使用pandas和pandasql库进行读取和... 目录如何用SQL语言查询多个Excel表格如何使用sql查询excel内容1. 简介2. 实现思路3

Go语言实现将中文转化为拼音功能

《Go语言实现将中文转化为拼音功能》这篇文章主要为大家详细介绍了Go语言中如何实现将中文转化为拼音功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 有这么一个需求:新用户入职 创建一系列账号比较麻烦,打算通过接口传入姓名进行初始化。想把姓名转化成拼音。因为有些账号即需要中文也需要英

Go语言使用Buffer实现高性能处理字节和字符

《Go语言使用Buffer实现高性能处理字节和字符》在Go中,bytes.Buffer是一个非常高效的类型,用于处理字节数据的读写操作,本文将详细介绍一下如何使用Buffer实现高性能处理字节和... 目录1. bytes.Buffer 的基本用法1.1. 创建和初始化 Buffer1.2. 使用 Writ

深入理解C语言的void*

《深入理解C语言的void*》本文主要介绍了C语言的void*,包括它的任意性、编译器对void*的类型检查以及需要显式类型转换的规则,具有一定的参考价值,感兴趣的可以了解一下... 目录一、void* 的类型任意性二、编译器对 void* 的类型检查三、需要显式类型转换占用的字节四、总结一、void* 的

C++中实现调试日志输出

《C++中实现调试日志输出》在C++编程中,调试日志对于定位问题和优化代码至关重要,本文将介绍几种常用的调试日志输出方法,并教你如何在日志中添加时间戳,希望对大家有所帮助... 目录1. 使用 #ifdef _DEBUG 宏2. 加入时间戳:精确到毫秒3.Windows 和 MFC 中的调试日志方法MFC

深入理解C++ 空类大小

《深入理解C++空类大小》本文主要介绍了C++空类大小,规定空类大小为1字节,主要是为了保证对象的唯一性和可区分性,满足数组元素地址连续的要求,下面就来了解一下... 目录1. 保证对象的唯一性和可区分性2. 满足数组元素地址连续的要求3. 与C++的对象模型和内存管理机制相适配查看类对象内存在C++中,规

关于Java内存访问重排序的研究

《关于Java内存访问重排序的研究》文章主要介绍了重排序现象及其在多线程编程中的影响,包括内存可见性问题和Java内存模型中对重排序的规则... 目录什么是重排序重排序图解重排序实验as-if-serial语义内存访问重排序与内存可见性内存访问重排序与Java内存模型重排序示意表内存屏障内存屏障示意表Int

C语言线程池的常见实现方式详解

《C语言线程池的常见实现方式详解》本文介绍了如何使用C语言实现一个基本的线程池,线程池的实现包括工作线程、任务队列、任务调度、线程池的初始化、任务添加、销毁等步骤,感兴趣的朋友跟随小编一起看看吧... 目录1. 线程池的基本结构2. 线程池的实现步骤3. 线程池的核心数据结构4. 线程池的详细实现4.1 初