《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

《C++笔记 第一部分 C++语言篇》第3章 内存模型及名字空间
 变量的说明限定符
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++标准的名字空间属性
声明区:可以进行声明的区域
潜在的作用域:变量潜在的作用域,从声明点,到声明区结尾

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

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

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

3.5引用

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

#include <iostream>
using namespace std;

void f1() {
	int a = 20;
	int &b = a;//创建引用类型变量时,要立刻 "赋值"
	int c = 100;
	b = c;
	cout<<b<<endl;//100
	cout<<a<<endl;//100
	cout<<&a<<endl;// 0x7fffcaa6ca10
	cout<<&b<<endl;// 0x7fffcaa6ca10
}

void f2(int *p) {
	*p = 21;
}

void f3(int &r) {//int &r = age
	r = 22; //age=22
}

int main() {
f1();

	int age = 20;
	//调用函数,让age的值改变为21
	f2(&age);
	cout<<"age="<<age<<endl;//age=21
	//调用函数,让age的值改变为22; 但是不能使用指针

	f3(age);
	cout<<"age="<<age<<endl;//age=22
	return 0;
}

结果如下所示:

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

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     argc
               argv
  * @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;
}