C++教程part1_namespace & namespace的内存分配

1.namespace的用法

7点内容:

#include 
#include "game1.h"
#include "game2.h"

// 1.resolve name conflicts
void test01()
{
    LOL::goAttack();//game1.h
    KingGlory::goAttack();//game2.h
}

//2. you can put variables, functions, structures, classes in namespace.
namespace A{
    int m_A;
    void func();
    struct Person{};
    class Animal{};
}

void test02()
{
    // 3.namespace must be declared under the global scope.
    // namespace definition is not allowed in local fields.
#if 0
    namespace B{
        int m_B;
    }
#endif
}

//4. namespace can be nested within namespace
namespace B{
    int m_A = 10;
    namespace C{
        int m_A = 20;
    }
}

void test03()
{
    std::cout << "B_m_A = " << B::m_A << std::endl;
    std::cout << "C_m_A = " << B::C::m_A << std::endl;
}

// 5.namespace is open,and content can be added at any time.
namespace B
{
    int m_B = 100;
} // namespace B

void test04()
{
    std::cout << "B_m_A = " << B::m_A << std::endl;
    std::cout << "B_m_B = " << B::m_B << std::endl;
}

// 6.namespace can be anonymous
namespace{
    // Equivalent to static 
    int m_C = 333;//static m_C
    int m_D = 444;//static m_D
}

void test05()
{
    std::cout << "m_C = " <<m_C <<std::endl;
    std::cout << "m_D = " << ::m_D << std::endl;
}

//7. namespaces can have aliases.
namespace LongName{
    int m_E = 10000;
}

void test06()
{
    namespace ShortName = LongName;
    std::cout << "namespace aliases:" << std::endl;
    std::cout << "ShortName::m_E::" <<ShortName::m_E << std::endl;
}

int main()
{

    test01();
    test03();
    test04();
    test05();
    test06();

    return EXIT_SUCCESS;
}

2.using声明和using编译指令可以使用在全局,此时全局展开!!!

2.1.using的全局编译指令

#include 

namespace KingGlory{
    int m_a;
    class attack{
        int m_b;
        int m_c;
    public:
        void display()
        {
            std::cout << "call KingGlory::display \n";
        }
    };
    void func()
    {
        std::cout << "call KingGlory::func\n";
    }
namespace Tank{
    int m_m_a;
    void func()
    {

        std::cout << "call KingGlory::Tank::func\n";
    }
}
}
using namespace KingGlory;//这里在全局作用域下声明,将会全局展开

void test01()
{
    KingGlory::attack atk;
    atk.display();
    KingGlory::func();
    KingGlory::Tank::func();
}

void test02()
{
    func();//由于进行了KingGlory的全局展开,可以直接调用
}

void test03()
{

}

void test04()
{

}

void test05()
{

}

int main()
{
    test01();
    test02();
    test03();
    test04();
    test05();

    return EXIT_SUCCESS;
}

2.2using的全局声明

#include 

namespace KingGlory{
    int m_a;
    class attack{
        int m_b;
        int m_c;
    public:
        void display()
        {
            std::cout << "call KingGlory::display \n";
        }
    };
    void func()
    {
        std::cout << "call KingGlory::func\n";
    }
namespace Tank{
    int m_m_a;
    void func()
    {

        std::cout << "call KingGlory::Tank::func\n";
    }
}
}
using KingGlory::func;
using KingGlory::m_a;

void test01()
{
    func();
    m_a = 100;
}

void test02()
{

}

void test03()
{

}

void test04()
{

}

void test05()
{

}

int main()
{
    test01();
    test02();
    test03();
    test04();
    test05();

    return EXIT_SUCCESS;
}

3.namespace的内存分配

一、namespace 中的类

  • 类声明只是告诉编译器这个类型的“蓝图”,它不分配内存。
  • 只有你在代码中实例化(定义)了这个类的对象,才会分配内存(在栈上或堆上,取决于如何实例化)。
  • namespace 只是一个作用域管理工具,为类型和变量提供命名空间,方便区分不同模块的符号。

举例:

KingGlory::attack atk;  // 这里才实例化对象,分配内存

这时程序会为 atk 分配内存。


二、namespace 中的基本类型变量

namespace KingGlory {
    int m_a;
}
  • 这是变量的定义,而非仅仅声明,是一个对象,所以会在程序的数据区静态分配内存(全局变量存储区)。
  • 变量的内存布局由编译器在编译阶段安排,属于静态存储期,程序启动时就分配了内存。
  • 不论你是否访问这个变量,内存都会被分配(除非优化器去掉未使用变量)。

举例:

std::cout << KingGlory::m_a << std::endl;

这行代码直接访问了变量。


三、命名空间中的变量是模板吗?

  • 变量不是模板,它是具体的存储对象。
  • 只有模板(template)才是蓝图,变量是具体实例。
  • namespace 变量直接是静态存储对象。

四、变量内存分配时机

  • 全局变量(如 namespace 变量)在程序开始时分配内存,属于静态存储期。
  • 不会等到第一次访问才分配。
  • 这和函数内的局部变量不同,局部变量是在运行时进入作用域时分配在栈上。

五、namespace 中的 const 和引用变量

namespace KingGlory {
    const int m_c = 100;
    const int& m_r = m_c;
}
  • const 变量默认具有内部链接(internal linkage),除非加 extern
  • 编译器通常会将 const 变量当做常量直接内联(常量折叠),不会单独分配内存(如果其地址未被取)。
  • 但如果取地址或引用,则会分配内存。
  • 引用本身不是对象,不占用内存,引用是某个对象的别名。
  • 在上例中,m_r 是对 m_c 的引用,不单独分配内存,只是 m_c 的别名。

六、举例说明

namespace KingGlory {
    int m_a = 10;               // 一定分配内存(静态区)
    const int m_c = 100;        // 可能不分配内存,直接内联
    const int& m_r = m_c;       // 引用,不分配内存
    static int m_s = 20;        // 静态变量,分配内存,仅限本文件内访问
    extern int m_ext;           // 声明,未定义不分配内存

    void func() {
        std::cout << "func\n";
    }
}

// 定义 extern 变量
int KingGlory::m_ext = 50;
  • m_am_s 会分配内存。
  • m_c 可能不分配内存,如果没取地址,直接作为编译时常量使用。
  • m_r 是引用,不占用内存。
  • m_ext 定义在外部,需要分配内存。

七、总结

类型 是否分配内存 分配时机 备注
namespace 中声明的类(类型) 不分配 无(类仅模板) 只有实例化才分配内存
namespace 中的基本类型变量 分配 编译期,程序启动时 静态存储区
namespace 中的 const 变量 可能不分配(常量折叠) 取地址时分配 默认内部链接,编译时优化
namespace 中的 const 引用 不分配 引用是别名,不占用内存
namespace 中的函数 不分配对象内存 代码区,函数体只存在一份

八、示例运行说明

void test01() {
    KingGlory::attack atk;   // 实例化,分配内存
    atk.display();

    KingGlory::func();       // 调用函数,无对象内存概念

    KingGlory::Tank::func();   // 嵌套命名空间函数调用
}
  • atk 是对象,分配内存。
  • 函数调用不涉及变量内存,只是执行代码。
  • 变量 KingGlory::m_a 已经在程序启动时分配内存,无需首次调用时分配。

你可能感兴趣的:(C++教程part1_namespace & namespace的内存分配)