目錄
- c語言中的問題
- 命名空間的定義
- 注意事項
- 第一點:同名命名空間
- 第二點:命名空間中的全局變量與局部變量
- 命名空間的使用
- 第一種使用方法
- 第二種使用方法
- 第三種使用方法
- 注意事項
- 第一點:沒有名字的命名空間
- 第二點:局部優先原則
- 第三點:命名空間和結構體
c語言中的問題
大家在學習c語言的時候有沒有發現一個問題,就是我們在創建變量的時候,如果兩個變量的名字是一樣的話就會報出變量重定義的問題,比如說下面的代碼:
#include<stdio.h>
int main()
{int num = 10;int num = 10;return 0;
}
我們將此代碼運行一下就可以發現我們這里會報出一個錯誤:
但是我們在編寫一個大的項目的時候會創建許許多多的變量出來,而且一個大型的項目一般都是分給多個人來完成,每個人負責編寫一些文件,最后再通過#include" 文件名"
將不同程序員寫的不同的文件合并到一起,但是這樣我們就會出現一個問題就是,我們這里不同的人會創建出不同的變量,這些變量有著不同的作用和功能,但是他們可能會有同樣的名字,因為程序員在寫的時候他是不知道其他程序員是怎么想的,比如說一號程序員在寫的時候為了記錄一個函數的返回值他就創建了一個整型的變量并且將其取名為:ret,而另一個程序員在編寫程序的時候為了得到另一個函數的返回值也創建一個名為ret的整型變量,這樣的話我們將這兩個程序員寫的文件合并到一起去的時候是不是就可能出現這個問題啊,比如說下面的代碼:
#include<stdio.h>
#include<stdlib.h>
int rand = 10;
int main()
{printf("%d", rand);return 0;
}
這段代碼創建了一個全局變量rand,然后我們想在main函數里面打印一下這個rand的值,但是我們這里引入stdlib.h
這個文件,在這個文件里面也使用了rand這個名字,如果我們不知道有這件事并且運行這段代碼的話,我們就會發現這里就會報出許多錯誤出來:
而且一個大型的項目所需要的變量和函數是非常的多的,而這就會大大的增加因名字相同而出現問題的概率,那么為了解決這個問題我們c++就增加了一個新的內容叫命名空間。分析了c語言出現的問題原因,不同的程序創建出來的不同的變量可能會有取同樣的名字,這樣在匯總的時候就會導致出現重定義的問題,那么c++就對此給出了一個解決方法:對這些變量再加上一層包裝,并且程序員還要對這些包裝取一個名字,在這個包裝里面程序員可以添加自己想要創建的變量,定義的函數,以及結構體等等。比如說一號程序員創建了一個命名空間名為one,二號程序員創建了一個命名空間名為two,這樣兩個程序員即使在命名空間中使用了相同的變量名也不會出現錯誤。
命名空間的定義
要想使用命名空間我們就得先來認識關鍵字:namespace,他的使用模板就如下:
首先寫一個namespace,然后在后面寫上這個命名空間的名字,然后在下面加一個大括號,這個大括號里面放的就是你們想創建的變量或者結構體或者函數等等,比如我們下面的代碼:
#include<stdio.h>
namespace ycf
{int a = 10;struct student{int age;char name[20];char sex[10];};int add(int x, int y){return x + y;}
}
int main()
{return 0;
}
這里就創建了一個命名空間,給命名空間取名為ycf在命名空間中創建整型變量a將其初始化為10,定義了一個add函數創建一個結構體,那么這就是ycf命令空間里面的內容,當然我們這里可以創建多個命名空間不止這一個。那么這就是我們定義命名空間的全部內容,當然這里還有一些注意事項希望大家注意一下。
注意事項
第一點:同名命名空間
如果有多個名字相同的命名空間,那么我們的編譯器就會自動地將這些命名空間進行合并,合并成同一個名字的命名空間,比如說下面的代碼:
#include<stdio.h>
namespace a
{int b = 10;int c = 20;
}
namespace a
{double e = 1.0;double f = 2.0;
}
int main()
{return 0;
}
這里創建了兩個命名空間,但是他們的名字是一樣的,那么編譯器就會將這兩個命名空間合并成一個,也就變成了這樣:
#include<stdio.h>
namespace a
{int b = 10;int c = 20;double e = 1.0;double f = 2.0;
}int main()
{return 0;
}
第二點:命名空間中的全局變量與局部變量
命名空間中定義的變量是全局變量,只有定義在函數里的變量才是局部變量。
namespace ycf
{int ret=10;;int add(){int a=10;int b=10;return a+b;}
}
int main()
{return 0;
}
這段代碼中ret變量雖然在命名空間當中但是他是屬于全局變量的,在程序運行的過程中就已經創建成功了,而函數中的變量a b則是只有在調用函數add的時候才會進行創建屬于局部變量。
命名空間的使用
第一種使用方法
第一種方法使用限定符::
來訪問命名空間中的變量。使用方法就是左邊放置命名空間的名稱右邊放置你想要使用的命名變量,可以通過下面的例子來學習·:
#include<stdio.h>
namespace a
{int b = 10;int c = 20;double e = 1.0;double f = 2.0;
}int main()
{printf("%d\n", a::b);printf("%f\n", a::e);return 0;
}
我們這里想打印命名空間里面的變量b和e的值,那么我們這里就用printf函數,在限定符::
的左邊填入命名空間的名字,右邊填入該命名空間中你想使用的變量或者類型的名字。
第二種使用方法
第二種方法需要使用using將命名空間中某個成員引入。我們上面講過命名空間相當于是一個包裝,將不同或者相同的變量或者類型裝在一起,我們要想使用這些變量的話就得用限定符,但是有時候命名空間里面的變量我們會經常用到,不斷使用第一種方法必定會讓我們感到煩躁所以第二種方法就是直接使用,將命名空間中的特定變量解放出來,那么這里的方法就是這樣:using 命名空間 具體對象名
比如下面的代碼:
#include<stdio.h>
namespace a
{int b = 10;int c = 20;double e = 1.0;double f = 2.0;int add(int x, int y){return x + y;}
}
using a::c;
using a::f;
int main()
{printf("%d\n", c);printf("%f\n", f);return 0;
}
通過這個代碼大家應該就可以發現:我們將c和f釋放之后,我們再使用命名空間里面的c和f的時就可以跟正常的變量一模一樣了,但是這個方法大家要注意的一點就是我們這里將常用的東西進行展開之后我們在自己定義變量的時候就得避免重名。
第三種使用方法
第三種方法就是將命名空間全部釋放,使用using namespace和該命名空間的名字便可以完成全部解放比如下面的代碼:
#include<stdio.h>
namespace a
{int b = 10;int c = 20;double e = 1.0;double f = 2.0;int add(int x, int y){return x + y;}
}
using namespace a;
int main()
{printf("%d\n", c);printf("%f\n", f);printf("%d\n", add(10, 20));return 0;
}
這樣我們在使用該命名空間里面的所有東西的時候都無需使用該限定符,但是這里大家要注意的一點就是:我們平時寫代碼做一些小的項目的時候可以這么使用,但是以后進入公司寫一些大項目的時候就不要這么寫了。
注意事項
第一點:沒有名字的命名空間
大家可能會看到有關限定符的這種寫法就是在限定符的左邊什么都沒有,比如說這樣:printf("%d", ::a);
我們知道限定符的左邊填入的是命名空間的名字,那如果我們這里不填入呢?那他表示的意思就是我們要引入一個命名空間里面的一個變量或者類型,但是這個命名空間的名字為空,那大家這里想想,什么樣的命名空間沒有名字呢?那是不是就只能是全局變量了,所以當::
左邊為空的時候,右邊的那些變量就表示的是沒有被封裝到命名空間里面的全局變量,比如說下面的代碼:
#include<stdio.h>
namespace n1
{int a = 10;
}
namespace n2
{int a = 20;
}namespace n3
{int a = 30;
}namespace n4
{int a = 40;
}
int a = 50;
int main()
{int a = 60;printf("%d", ::a);return 0;
}
大家看看這段代碼,我們這里要打印::a
的值,但是我們左邊沒有給他的命名空間的名字,所以他這里就會在跑到我們的全局變量去找這里的a,因為我們這里在全局變量中定義了一個a,并將其值初始化為50,所以我們這里打印的值就是50
但是大家有沒有想過一個問題,為什么這里打印的為什么不是60呢?如果大家有這樣的疑問的話就得把文章往上翻看到這么一句話:命名空間中定義的變量是全局變量,只有定義在函數里的變量才是局部變量。而這個::
限定符他的作用就是訪問命名空間里面的內容的,而命名空間里面的內容又全部都是全局變量不可能是局部變量,所以我們這里訪問的值都是全局變量,所以當我們不給他要訪問的命名空間的名字的時候,他要訪問也是訪問全局變量,所以這里打印的就是50,如果我們將這個全局變量的a去掉的話我們來看看會發生什么?
我們發現他這里就直接報錯了,所以這里大家要注意一下這種使用的情況。
第二點:局部優先原則
局部優先原則,我們在使用一個變量的時候,編譯器會先在局部中查找這個變量,如果局部沒有找到的話他就會在全局中查找這個變量比如說下面的這個代碼:
#include<stdio.h>
int a = 10;
int main()
{int a = 20;printf("%d", a);return 0;
}
這段代碼的運行結果就是20,因為在局部中定義了該名字的變量并將其值賦值為20,那么在c++中如果你想使用某個命名空間中的變量或者內容,但是該空間沒有的話他是不會在其他地方尋找的比如說下面的代碼:
#include<stdio.h>
namespace N
{int a = 10;
}
int b = 10;
int main()
{int b = 10;printf("%d", N::b);return 0;
}
我們在全局和局部中都定義了一個名為b的局部變量,但是我們在命名空間N中卻沒有定義該變量,那么我們下面要使用N中的變量b時,他就只會去命名空間N中查找該變量,如果沒找到他也不會去其他的地方進行查找,而是直接報錯,那么我們來看看這里代碼的運行結果:
同樣的道理我們再來看看下面的代碼:
#include<stdio.h>
namespace N
{int a = 10;
}
int main()
{int a = 10;printf("%d", ::a);return 0;
}
我們這段代碼是在命名空間N和局部中定義了一個變量a,但是沒有在全局變量中定義一個變量a,那這時我們要打印全局變量中的變量a的話就只會在全局變量中查找,如果全局找不到也不會去局部和命名空間中查找而是直接報錯,那么我們將這段代碼運行之后就會報錯:
第三點:命名空間和結構體
我們可以在命名空間里面定義一個結構體,就好比這樣:
#include<stdio.h>
namespace N
{struct student{ int age; char name[20];char sex[10]; };
}
int main()
{return 0;
}
但是我們在使用這個結構體的時候就得這樣:先寫struct +命名空間名+限定符+定義的結構體的類型名+結構體的名字,就好比如下這樣:
#include<stdio.h>
namespace N
{struct student{ int age; char name[20];char sex[10]; };
}
int main()
{struct N::student ycf = { 0 };return 0;
}
我們來看看這個能不能編譯成功:
那么我們這里就是編譯成功的,如果我們對這個結構體加上typedef進行重命名的話我們這里就得做出一些改變我們就可以將這里的struct去掉,將后面的定義的結構體的類型名改成新的名字即可,比如下面的代碼:
#include<stdio.h>
namespace N
{typedef struct student{int age;char name[20];char sex[10];}student;
}
int main()
{N::student ycf = { 0 };return 0;
}