欢乐C++ —— 5. 其它基础
深拷贝,浅拷贝
简述
通俗点讲,深复制与浅复制一般对指针而言,深拷贝复制指针所指向的内容,浅拷贝复制指针的值。
举例
当我们有现在有指针A指向一块数据,和指针B。那么经过深浅拷贝后它们的关系如下。
深拷贝 —— B拥有了A的数据拷贝副本。浅拷贝—— B只是简单的复制了A指针的值。
深浅复制的优缺点
说优缺点有点不准确,准确来说应该是特点:
- 深拷贝:各指针独有一份数据,两块数据之间相互独立。不过费时间费空间。
- 浅拷贝:省时省空间,两指针指向同一块数据,有可能出现通过一个指针误修改数据而影响到另一个指针。
指针和引用
-
引用本质上是自身为常量的指针。
定义一个引用/指针和使用一个引用/指针,在底层的汇编指令都是相同的。
所以比普通指针更安全,因为自身为常量在定义是必须初始化,所以没有空引用和野引用。所以一经初始化则不能更改。
-
编译器自动为使用引用变量的地方解引用。
所以,引用自身的值永远不会被访问到。而指针变量的值可以访问到。
-
指针有多级,而引用只分为左值引用和右值引用。
-
引用逻辑上不占空间,利用这个概念可以来理解一些看上去比较奇怪的东西。例如为什么没有引用数组,容器中不能放置引用等等。
命名空间
大型程序往往会使用多个独立开发的库,这些库又会定义大量的全局名字。当应用程序用到多个库时,不可避免的发生某些名字相互冲突的情况。当多个库将名字放置在全局命名空间中将引发命名空间污染。
命名空间 为防止名字冲突提供了更加可控的机制。命名空间分割了全局命名空间,其中每个命名空间是一个作用域。通过在某个命名空间中定义库的名字,库的作者可以避免全局名字的限制。
防止全局的符号冲突。
基础使用
-
namespace 空间名称 :
namespace second // 产生了一个作用域 { int gdata1 = 10; int gdata2 = 10; int gdata3 = 10; }
-
using 符号声明: 声明一个符号。
using std::cout; using std::endl; using second::gdata1;
-
using namespace 空间名称 声明一个空间内所有符号。
using namespace std; using namespace second;
全局命名空间
全局作用域中定义的名字实际上是定义在全局命名空间中。全局命名空间以隐式的方式声明,全局作用域内定义的名字被隐式地添加到全局命名空间中。
int n;
int main(){
::n;
}
未命名地命名空间
未命名的命名空间定义的名字作用域与该命名空间所在的作用域相同。
原先,需要将名字声明为static 使得其在整个程序运行期都存在,但是其无法被其它文件使用。而使用匿名命名空间可以延长名字的生存期,而不会限制它的作用域。
命名空间别名
namespace NS = MySpace;
左右值
可以见这篇博文 https://www.cnblogs.com/starrys/p/13157586.html
常变量
在 .cpp 文件中,内置类型常量在编译时就会被替换。
而 .c 文件中,内置类型常量更称为常变量。
下面的代码,在.c .cpp 不同文件下会有不同效果。
#include <stdio.h>
int main( )
{
const int a = 10;
int *p = &( int ) a;
*p = 666;
printf("%d , %d", *p, a);
return 0;
}
在 .cpp 下会输出 666 , 10
而在 .c 下会输出 666 , 666
这个其实是C++编译器的一个优化。
固有的不可移植属性
继承自C:
- 位域:当一个设备向其它程序或硬件设备传递二进制数据时通常会用到它。
- volatile 限定符:让寄存器每次去内存取变量的值。通常情况下,编译器会做优化,将某个经常用到的变量从内存保存到寄存器中,进行一系列操作后再写回内存。而volatile 则使每次操作该变量都从内存中读值。
新增:
- 链接指示:有时候C++ 会调用C 语言写的函数,这时候可以使用链接指示来向编译器声明它是一个C 函数。