c++ Primer Plus(第九章)

第九章 内存模型与命名空间

  1. 程序的三部分

    • 头文件 :包含结构声明和使用这些结构的函数的原型
    • 源代码文件:包含与结构相关的函数的代码或者包含调用与结构相关的函数的代码,所以在main中只用包含头文件即可。
    • 不要将函数定义或者变量声明放到头文件,因为其他文件如果包含这个头文件并且有定义这个函数,将会导致重复定义
    • 被定义为const的变量可以放到头文件中
    • 自己定义的头文件用”f.h”引用,<>表示编译器去标准库中找,双引号表示优先正在当前目录找,或者其他目录,取决于编译器
    • 不要在源代码文件中使用#incldue包含其他源文件,将会导致多重声明
    • 使用#ifndef XX #definne #endif 并不能保证源文件不被重复包含,只是保证编译器只读这个文件一次,但是如果这个文件本身就有重复定义的情况,比如相互引用,那么依然会出错

    2.多个库的链接问题

    • c++标准允许每个编译器设计人员以他认为合适的方式实现名称修饰(参考我的另一篇博客),因此由不同的不同编译器创建的二进制模块很可能无法正确链接(.o)文件。即两个不同的编译器将会为同一个函数生成不同的修饰名称。所以在链接编译模块的时候,请确保所有对象文件或库都是同一个编译器产生的。即.o文件是同一个编译器生成即可

    3.自动存储持续性

    +自动存储特性:在函数定义中声明的变量(包括函数参数),只在声明的代码块中生效

    • c++11中的autoregister与之前的c语言和c++语言不一样。auto变量表示自动确定变量类型,register表示显式指明这是一个自动变量,不在表示建议编译器使用寄存器

    4.静态存储

    • c++为静态存储持续性变量提供了三种链接性:外部链接性(可在其他文件中访问),内部链接性(只能在当前文件中访问,必须要有包含他的代码才能使用)和无连接性(只能在当前函数或者代码块中访问)。三种方式其都在整个程序的执行期间存在。如果没有显式的初始化静态变量,编译器默认设置为0(静态数组与结构中每个元素或者成员都设置为0,指针将会被表达为合适类型)
    • 传统的K&R c不允许初始化自动数组和结构,但允许初始化静态数组与结构,但标准c和c++允许对这两种进行初始化,但是某些旧的编译器可能不支持

5.static的用法

  • 用于局部变量声明,以指出变量是无链接性的静态变量,static表示存储持续性,用于代码块外的声明时,static表示内部链接性,而变量已经是静态持续性了,又有人称之为关键字重载。
    upload successful

6.动态初始化

  • 编译器将在编译后对常量表达式初始化,x=13* 13这种叫常量表达式

7.静态持续性,外部链接性

  • 在每个使用外部变量的文件中,都必须声明它,又应为c++中变量只能声明一次,所以c+为了全局变量在各个文件中使用,提供了两种声明方式,一种定义声明(分配空间),另一种引用声明,表示使用其他文件的变量,引用声明使用关键字extern,且不进行初始化,否则声明为定义,分配空间
  • 如果这个文件中代码块有全局变量重名的局部变量,全局变量将被隐藏,如果要使用全局变量,使用作用域解析符::.比如 ::x表示使用全局的变量而非局部变量

8.静态持续性,内部链接性

  • statcic限定符将变量连接性限制为内部的,连接性为内部的变量只能在其所属的文件中使用
  • 静态变量如果与常规外部变量重名,那么静态变量将隐藏外部常规变量,如果同时出现两个外部常规变量,那么将报错
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
l.cpp
int c = 50;

static int b = 50;

main.cpp
#include <iostream>

using namespace std;

extern int c;

//extern int a;

int main()

{

    cout << "Hello World!\n";

       cout << c << endl;

       //cout << a << endl;

}
  • 全局变量只能在.cpp文件定义,并且访问全局变量不需要包含这个全局变量的文件,一旦使用include相当于这个文件被包含,即使用include可以使用另一个文件定义的static全局变量

9.cv-限定符

  • 即const,volatile,volatile表示即使程序代码没有对内存单元进行修改,其值也可能变化,目的是改善编译器的优化能力

10.mutable

  • 用mutable来指出即使结构或者类变量为const,其某个成员也可以被修改,。

11.const对存储特性的改变

  • 全局定义的const等价与类似了static关键字,即具有内部链接性,这样定义常量就很方便,即需要常量的文件只需要包含常量头文件即可,不需要担心重复的问题
  • 如果出于某种原因,希望常量连接性为外部,extern const in s=0;这样声明即可

12.函数的链接性

  • 默认为外部链接性,即所有文件只能有一个同名函数(不包括重载)
  • 可以使用static关键字改变为内部的
  • 对于静态函数,如果定义了与库文件同名的,那么编译器优先在自己定义的里面找

13.语言的连接性

  • 由于名称修饰的问题,所有c和c++的同一个库函数的所打上的数字名称可能不一致 需要使用如下 extern "c"void spiff(int) 这样指明是c还是c++

14.储存方案与动态分配

  • 对于内置的类型,比如int,方式为 int * p=new int(6)
  • 对于数组 :int * a=new int[2] {2,3}//c++11
  • 对于结构体 T* a =new a{….};//c++11
  • c++11new失败后返回的是std :: bad_alloc,而不是空指针
  • 定位new运算符: 需要加头文件,让new分配到指定空间
    使用方式 p=new(addr) int[6]

13.名称空间

  • 使用namespace 关键字定义,但是应该要注意,名称空间中应该有完整的定义和声明
  • 名称空间可以是全局的,也可以是另一个名称空间的,通常为外部链接性,除非使用了常量字符串
  • 名称空间是开放的,可以把已有名称加入到自己的名称空间,但是要注意,如果在一个名称空间中使用了using namespace xxx那么如果在外部使用了这个名称的using,那么两个都将是可见的了(可传递)
  • 匿名的名称空间:链接性为内部的代替方法
  • 名称空间的添加,使用 和之前一样的 namespace names{xxx}:xxx为要添加的东西
  • 两个嵌套的名称空间的引用是 names1::name2::val;
  • 对名称空间起别名的方式 是 namespace m=m_v_F;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
.h文件
#pragma once

namespace jack

{

       int a=10;//变量的声明和定义应该在一起;

       int b;

       int c;

       void f();

}

.cpp文件
#include <iostream>

namespace jack

{

       void f()

       {

              std::cout << "s";

       }

}

main文件
#include <iostream>

#include "name.h"



int main()

{

       jack::f();

       std::cout << jack::a << std::endl;

    std::cout << "Hello World!\n";

}