C++ 命名空間避免命名沖突的實(shí)現(xiàn)
??名字沖突問(wèn)題
在實(shí)際生活中,一個(gè)大型的項(xiàng)目往往不是一個(gè)人獨(dú)立完成的,而是由若干個(gè)人合作完成的,不同的人分別完成不同的部分,最后組合成一個(gè)完整的程序。
假如不同的人分別定義了類(lèi),放在不同的頭文件中,在主文件(包含主函數(shù)的文件)需要用這些類(lèi)時(shí),就用#include指令將這些頭文件包含進(jìn)來(lái)。
由于各頭文件是由不同的人設(shè)計(jì)的,有可能在不同的頭文件中用了相同的名字來(lái)命名所定義的類(lèi)或函數(shù)。這樣在程序中就會(huì)出現(xiàn)名字沖突。
??例子
程序員甲在頭文件header1.h中定義了類(lèi)Student和函數(shù)fun:
#pragma once
//header1.h
#include <iostream>
#include<string>
#include <cmath>
using namespace std;
class Student //聲明Student類(lèi)
{
public:
Student(int n, string nam, int a)
{
num = n;
name = nam;
age = a;
}
void get_data();
private:
int num;
string name;
int age;
};
//成員函數(shù)的定義
void Student::get_data()
{
cout<< num <<"" << name << "" << age << endl;
}
//定義全局函數(shù)(即外部函數(shù))
double fun(double a, double b)
{
return sqrt(a + b);
}
在main函數(shù)所在的主文件中包含文件header1.h:
#include "header1.h"
int main()
{
Student stud1(101,"Wang",18);
stud1.get_data;
cout<<fun(5,3)<<endl;
return 0;
}
運(yùn)行結(jié)果如下:

如果程序員乙寫(xiě)了頭文件head2.h,在其中定義了其他類(lèi)以外,還定義了類(lèi)Student和函數(shù)fun,但其內(nèi)容與頭文件header1.h中的Student和函數(shù)fun有所不同。
//header2.h
#pragma once
#include <string.h>
#include<cmath>
#include<iostream>
using namespace std;
class Student
{
public:
Student(int n, string nam, char s)//參數(shù)與header1.h中不同
{
num = n;
name = nam;
sex = s;
}
void get_data();
private:
int num;
string name;
char sex;
};
//成員函數(shù)定義
void Student::get_data()
{
cout << num << "" << name << "" << sex << endl;
}
//定義全局函數(shù)
double fun(double a, double b)
{
return sqrt(a - b);//返回值與header1中的fun函數(shù)不同
}
......
//頭文件2可能還有其他的內(nèi)容
假如主程序員在其程序中要用到header1.h中的Student和函數(shù)fun,因而在程序中包含了頭文件header1.h,同時(shí)又要用到頭文件header2.h中的一些內(nèi)容,但是不知道此時(shí)header2.h中包含了與header1.h同名單內(nèi)容不同的Student類(lèi)和fun函數(shù),因而又在頭文件中包含了頭文件header2.h。
主文件如下:
//main file
#include <iostream>
#include "header1.h"
#include "header2.h"
int main()
{
Student stud1(101,"Wang",18);
stud1.get_data;
cout<<fun(5,3)<<endl;
return 0;
}
這時(shí),程序編譯就會(huì)出現(xiàn)錯(cuò)誤。

??名字沖突
因?yàn)樵陬A(yù)編譯后,頭文件中的內(nèi)容取代了對(duì)應(yīng)的#include指令,這樣就在同一個(gè)程序文件中出現(xiàn)了兩個(gè)Student類(lèi)和兩個(gè)fun函數(shù),顯然是重復(fù)定義,這就是名字沖突。
名字沖突,即在同一個(gè)作用域中含有兩個(gè)或多個(gè)同名的實(shí)體。
不僅如此,在程序中往往還需要引用一些庫(kù),包括C++編譯系統(tǒng)提供的庫(kù)、由軟件開(kāi)發(fā)商提供的庫(kù)或者用戶自己開(kāi)發(fā)的庫(kù),為此需要包含有關(guān)的頭文件。如果在這些庫(kù)中包含有與程序的全局實(shí)體同名的實(shí)體,或者不同的庫(kù)中有相同的實(shí)體名,則在編譯時(shí)就會(huì)出現(xiàn)名字沖突。有人稱(chēng)之為全局命名空間污染。
為了避免這類(lèi)問(wèn)題的出現(xiàn),人們提出了許多方法,例如:將實(shí)體的名字寫(xiě)得長(zhǎng)一點(diǎn)(包含十幾個(gè)或幾十個(gè)字母和字符);把名字搞得特殊一些,包括一些特殊的字符;由編譯系統(tǒng)提供的內(nèi)部全局標(biāo)識(shí)符都用下劃線作為前綴,如_complex(),以避免與用戶的實(shí)體同名;由軟件開(kāi)發(fā)商提供的尸體的名字用特定的字符作為前綴等。但是這樣的效果并不理想,而且增加了閱讀程序的難度,即可讀性降低了。
C語(yǔ)言和早期的C++語(yǔ)言沒(méi)有提供有效的機(jī)制來(lái)解決這個(gè)問(wèn)題,沒(méi)有庫(kù)的提供者能夠建立自己的命名空間。人們希望ANSI C++ 標(biāo)準(zhǔn)庫(kù)能夠解決這個(gè)問(wèn)題,提供一種機(jī)制、一種工具,使由庫(kù)的設(shè)計(jì)者命名的全局標(biāo)識(shí)符能夠和程序的全局實(shí)體名以及其他類(lèi)的全局標(biāo)識(shí)符區(qū)別開(kāi)來(lái)。
??命名空間
為了解決這個(gè)問(wèn)題,ANSI C++增加了命名空間。
所謂命命名空間,就是一個(gè)由程序設(shè)計(jì)者命名的內(nèi)存區(qū)域。程序設(shè)計(jì)者可以根據(jù)需要指定一些有名字的空間域,把一些全局實(shí)體分別放在各個(gè)命名空間中,從而與其他全局實(shí)體分離開(kāi)來(lái)。
我的理解就是原來(lái)我們的全局實(shí)體變量都是“暴露出來(lái)”的,然后命名空間的作用就是分別個(gè)你需要的全局實(shí)體“圍起來(lái)”,像柵欄一樣,每一塊區(qū)域都有一個(gè)專(zhuān)屬于自己的名字。然后在編譯階段,就像是好多個(gè)“圍起來(lái)的柵欄”,且各不相同。
命名空間的作用是建立一些互相分隔的作用域,把一些全局實(shí)體分隔開(kāi)來(lái),以免產(chǎn)生名字沖突。
這里有一段很形象的描述,可以幫助大家更好地理解:例如,某中學(xué)高三年級(jí)有3個(gè)叫李相國(guó)的學(xué)生,如果都在同一班,那么老師點(diǎn)名叫李相國(guó)時(shí),3個(gè)人都站起來(lái)應(yīng)答,這就是名字沖突。因?yàn)樗麄儫o(wú)法辨別老師想叫的是哪一個(gè)李相國(guó)?同名者無(wú)法互相區(qū)分。為了避免同名混淆,學(xué)校把3個(gè)同名的學(xué)生分在3個(gè)班。這樣,在小班點(diǎn)名叫李相國(guó)時(shí),只會(huì)有一個(gè)人應(yīng)答。也就是說(shuō),在該班的范圍內(nèi),即班作用域內(nèi)名字是唯一的。如果在全校集合時(shí)校長(zhǎng)點(diǎn)名,需要在全校范圍內(nèi)找這個(gè)學(xué)生,要考慮的作用域是全校范圍。如果校長(zhǎng)叫李相國(guó),全校學(xué)生中又會(huì)有3個(gè)人一齊喊“到”,因?yàn)樵谕蛔饔糜蛑写嬖?個(gè)同名學(xué)生。為了在全校范圍內(nèi)區(qū)分這3名學(xué)生,即加上班名限定。這樣就不會(huì)產(chǎn)生混淆。
可以根據(jù)需要設(shè)置許多個(gè)命名空間,每個(gè)命名空間代表一個(gè)不同的命名空間域,不同的命名空間不能同名。這樣,可以把不同的庫(kù)中的實(shí)體放到不同的命名空間中,或者說(shuō),用不同的命名空間把不同的實(shí)體隱藏起來(lái)。過(guò)去用的全局變量可以理解為存在于全局命名空間,獨(dú)立域所有有名的命名空間之外,不是不需要namespace聲明的,實(shí)際上是由系統(tǒng)隱式聲明的,在該空間中有效。
??命名空間的類(lèi)型
在聲明一個(gè)命名空間時(shí),花括號(hào)內(nèi)不僅可以包括變量,而且還可以包括一下類(lèi)型:
- 變量(可以帶有初始化);
- 常量;
- 函數(shù)(可以是定義或聲明);
- 結(jié)構(gòu)體;
- 類(lèi);
- 模板;
- 命名空間(在一個(gè)命名空間中又定義了一個(gè)命名空間,即嵌套的命名空間)。
??命名空間的成員
例如:
namespace ns1 //指定命名空間ns1
{
int a;
double b;
}
- ns1是命名空間的名字。
- 在花括號(hào)內(nèi),聲明的實(shí)體即為命名空間的成員,包括全局變量a和b。
- 使用a和b,需要加上命名空間和作用域分辨符"::",如ns1::a,ns1::b。
- 需要注意的是,a和b仍然是全局變量,僅僅是把他們放在了命名空間中而已。
??命名空間的使用
舉例如下:
namespace ns1
{
const int RATE=0.08;//常量
double pay;//變量
double tax()//函數(shù)
{
return a*RATE;
}
namespace ns2 //嵌套命名空間
{
int age;
}
}
輸出命名空間中ns1中成員的數(shù)據(jù):
cout<<ns1::RATE<<endl;
cout<<ns1::pay<<endl;
cout<<ns1::tax()<<end;
cout<<ns1::ns2::age<<endl;
??使用命名空間解決名字沖突
聲明命名空間ns1,并在命名空間ns1中聲明Student類(lèi)和定義成員函數(shù)、定義fun函數(shù)。
#pragma once
//header1.h
#include <iostream>
#include<string>
#include <cmath>
using namespace std;
namespace ns1 {
class Student //聲明Student類(lèi)
{
public:
Student(int n, string nam, int a)
{
num = n;
name = nam;
age = a;
}
void get_data();
private:
int num;
string name;
int age;
};
//成員函數(shù)的定義
void Student::get_data()
{
cout << num << "" << name << "" << age << endl;
}
//定義全局函數(shù)(即外部函數(shù))
double fun(double a, double b)
{
return sqrt(a + b);
}
}
在header2.h中,聲明命名空間ns2,并在命名空間ns2中定義Student類(lèi)和 成員函數(shù)以及fun函數(shù)。
using namespace std;
namespace ns2
{
class Student
{
public:
Student(int n, string nam, char s)//參數(shù)與header1.h中不同
{
num = n;
name = nam;
sex = s;
}
void get_data();
private:
int num;
string name;
char sex;
};
//成員函數(shù)定義
void Student::get_data()
{
cout << num << "" << name << "" << sex << endl;
}
//定義全局函數(shù)
double fun(double a, double b)
{
return sqrt(a - b);//返回值與header1中的fun函數(shù)不同
}
}
主函數(shù)如下:
#include "header1.h";
#include "header2.h";
int main()
{
ns1::Student stud1(101, "Wang", 18);//用命名空間ns1中的Student類(lèi)定義stud1
stud1.get_data();
cout <<ns1:: fun(5, 3) << endl;//調(diào)用命名空間ns1中的fun函數(shù)
ns2::Student stud2(102, "Li", 'f');//用命名空間ns2中的Student類(lèi)定義stud2
stud2.get_data();
cout << ns2::fun(5, 3) << endl;//調(diào)用命名空間ns2中的fun函數(shù)
return 0;
}
運(yùn)行結(jié)果如下:

到此這篇關(guān)于C++ 命名空間避免命名沖突的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)C++ 命名空間避免命名沖突內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++?Boost?StringAlgorithms超詳細(xì)講解
Boost是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱(chēng)。Boost庫(kù)是一個(gè)可移植、提供源代碼的C++庫(kù),作為標(biāo)準(zhǔn)庫(kù)的后備,是C++標(biāo)準(zhǔn)化進(jìn)程的開(kāi)發(fā)引擎之一,是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱(chēng)2022-11-11
C++實(shí)現(xiàn)主機(jī)字節(jié)序和網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)換示例
這篇文章主要為大家介紹了C++實(shí)現(xiàn)主機(jī)字節(jié)序和網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)換示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11
C++面試題之進(jìn)制轉(zhuǎn)換的實(shí)例
這篇文章主要介紹了C++面試題之進(jìn)制轉(zhuǎn)換的實(shí)例的相關(guān)資料,希望通過(guò)本文能幫助到大家,讓大家理解掌握這樣的知識(shí),需要的朋友可以參考下2017-10-10
Qt6實(shí)現(xiàn)調(diào)用攝像頭并顯示畫(huà)面
這篇文章主要為大家詳細(xì)介紹了Qt6如何實(shí)現(xiàn)調(diào)用攝像頭并顯示畫(huà)面的效果,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以參考一下2023-02-02
C++中實(shí)現(xiàn)多態(tài)有幾種方式小結(jié)
在C++中,多態(tài)是一種面向?qū)ο缶幊痰奶匦?允許以統(tǒng)一的方式處理不同類(lèi)型的對(duì)象,并根據(jù)實(shí)際對(duì)象的類(lèi)型來(lái)執(zhí)行相應(yīng)的操作,本文給大家介紹了C++中實(shí)現(xiàn)多態(tài)有幾種方式小結(jié),需要的朋友可以參考下2024-12-12

