zoukankan      html  css  js  c++  java
  • (8)C++ 内存模型与名称空间

    一、单独编译

    头文件

    不要将函数定义或者变量声明放到头文件中,引入多个文件时可能会造成同一个函数定义多次

     引入头文件

    #include "文件名"

    File1.h

    #ifndef FILE1_H_
    #define FILE1_H_
    struct Student
    {
        int age;
    };
    #endif // !FILE1_H_

    File2.h

    #include "File1.h"

    main.cpp

    #include<iostream>
    #include "File1.h"
    #include "File2.h"
    
    using namespace std;
    
    void main() {
        Student stu = {20};
        cout << stu.age << endl;
    }

    这里的

    #ifndef FILE1_H_
    
    .....code
    #endif

    如果File2.h引入了头文件File1.h,并且main.cpp 同时引入了File1和File2两个头文件,这样会导致 Stuendt 会引入两回,编译器遇到这种情况会报编译错误。有了ifndef就会忽略重复引入的问题。

    这里的

    #define FILE1_H_

    当以前没有使用预处理器编译指令#define定义的名称 FILE1_H_时,才处理#ifndef #endif之间的语句。

    2.

    预编译会把.cpp 引用的头放入 cpp代码中

    例如 file1.cpp file2.cpp 都包含了 test.h 则,test.h的代码即会添加到file1文件,也会添加到file2文件。

    二、作用域

    作用域:变量等的使用范围。

    链接性:外部链接性(变量作用范围)可在文件间共享---全局变量,内部链接性只在当前文件中,无链接性只能在当前函数或代码块中---局部变量。

    1.自动变量

    函数内声明的变量,作用域只在函数内。

    如果代码块内部的变量名和外部的变量名相同,则内部变量作用在内部,外部变量作用在外部

    auto a = 3; //C++11后相当于 c# var

    这种变量存在栈中

    2.静态变量

    静态变量生命周期比自动变量的寿命更长,静态变量的数目在程序运行期间是不变的,所以不需要栈来管理,编译器会分配固定的内存块来存储它们,默认初始化为0。

    (1).如果想有外部链接性的静态变量

    必须在外部声明,并且不带static

    (2).如果想有内部链接性的静态变量

    必须在外部声明,并且带static

    (3).如果想有无链接性的静态变量

    必须在代码块内部声明,并且带static

    #include<iostream>
    using namespace std;
    int g = 10;//具有外部链接性的静态函数
    int static a = 3;//具有内部链接性的静态函数
    void main() {
    
    }
    void func() {
        int static b = 4;//无链接性的静态函数
        int c = 9;//自动变量,
    }

     3.静态和外部

    (1)单定义规则:整个程序中全局变量只能定义一次。

    C++有两种变量声明,1是定义声明(简称定义)给变量分配内存空间,2是引用声明(简称声明)不给变量分配内存空间因为它引用已有的变量。

    使用extern关键字并且不初始化,表示引用声明。用来表示该变量是来自外部的全局变量

    int a = 3;//定义声明
    extern int b = 3; //定义声明,因为进行了初始化
    extern int c;//这是真正的引用声明,不分配内存

    (2) 如果在文件中声明了一个与外部同名的变量,则该变量属于自动变量

     main.cpp

    #include<iostream>
    using namespace std;
    int a = 3;
    void main() {
    
    }

    test.cpp

    void func1() {
        extern int a;//全局变量
    }
    
    void func2() {
        int a;//自动变量
    }

    4.静态与内部 5.静态与无链接 略

    6.说明符和限定符

    volatile、mutable 待补

    const

    被const修饰的全局变量会变成内部链接性

    const int a = 3;//内部链接性
    void main() {
    
    }

    7.函数和链接性

    C++的链接性为静态的,整个程序执行期间都一直存在。

    static 修饰函数可以让函数变成内部的,前提是原型和函数定义必须都加上static 

    8.语言链接性

    C++中查询C++库函数和查询C库的方式不同。要区分它们

    extern "C" void fun1();//原型,使用C语言方式查找函数
    extern "C++" void fun2();//原型,使用C++方式查找函数
    extern void fun3();//原型,默认使用C++方式查找函数

    9.动态存储

    动态分配的内存由new和delet控制,而不是作用域和链接性的规则控制。

    编译器通常使用三块独立内存:静态变量、自动变量、动态存储。(可能会细分)

    定位new运算符??

    定位new一帮用于以下场合

    1. 硬件编程

      如果知道了硬件设备的地址,想要将那个硬件设备与一个C++类直接关联,那么定位new就非常有效了

    2. 实现基础库

      基础库一般为了效率要先预分配内存,然后在预分配的内存上执行构造,几乎所有的C++容器都用到了定位new

     

    三、名称空间

     1.C++传统的名称空间

     作用域

    2.C++名称空间新特性

    (1)using声明可以使用单个变量和函数

    using声明后在该区域内有效 

    #include<iostream>
    using namespace std;
    namespace space1{
        int a=3;
    }
    namespace space2 {
        int a=2;
    }
    void main() {
    
        cout << space1::a;//直接使用
        using space2::a;//using声明,避免每次调用时都要加::
        cout << a;
    }

    在外部使用using声明

    using space2::a;
    void main() {
    
        cout << a;//属于space2
    }
    
    void func1() {
        cout << a; //属于space2
    }

    (2)using 编译可以使用空间下的所有变量和函数

    using namespace space2;//使用using编译
    
    void main() {
    
        cout << a;//使用space2下
    }
    void func1() {
        cout << b; //使用space2下
    }

    如果using编译指令导入一个已经在函数中声明的名称,则会使用局部定义的变量

    void main() {
        using namespace space2;//
        int a = 9;
        cout << a;//结果 9
    }

    如果using声明导入一个已经在函数中声明的名称,会报多重错误

    void main() {
        using space2::a;//
        int a = 9;
        cout << a;//结果 9
    }

     全局 ::

    #include<iostream>
    using namespace std;
    int a=8;
    namespace space1 {
        int a = 3;
        int b = 6;
    }
    
    void main() {
        using namespace space1;
        int a = 9;
        cout << ::a;//全局的a 结果8 
    }

    尽量使用using声明减少不必要的麻烦 

    3.名称空间嵌套

    4.未命名名称空间

    5.名称空间开放性

    几个文件都使用namespace 里面的内容可以组合在一起?

    6.多文件

  • 相关阅读:
    kettle连接MySQL报错
    git切换到某个tag, 从tag切换回当前分支
    wireshark 实用过滤表达式(针对ip、协议、端口、长度和内容)
    linux下python3.6.7安装
    haproxy backup模式
    Oracle_2 随便写写
    Oracle 日期函数练习 随便写写
    RabbitMQ
    X.509标准、CA认证
    docker-compose和Dockerfile的volumes
  • 原文地址:https://www.cnblogs.com/buchizaodian/p/11541008.html
Copyright © 2011-2022 走看看