編程視界:C++命名空間

目錄

命名空間

為什么要使用命名空間

什么是命名空間

命名空間的使用方式

關鍵點總結

命名空間的嵌套使用

匿名命名空間

跨模塊調用問題

命名空間可以多次定義

總結


首先從C++的hello,world程序入手,來認識一下C++語言

#include <iostream>
using namespace std;int main(int argc, char * argv[]){cout << "hello,world" << endl;return 0;
}>

(1)iostream是C++的頭文件,為什么沒有后綴?—— 模板階段再作講解

(2)using namespace std是什么含義?—— 命名空間的使用

(3) cout << "hello,world" << endl; 實現了輸出hello,world的功能,如何理解這行代碼?—— cout的使用

命名空間

為什么要使用命名空間

一個大型的工程往往是由若干個人獨立完成的,不同的人分別完成不同的部分,最后再組合成一個完整的程序。由于各個頭文件是由不同的人設計的,有可能在不同的頭文件中用了相同的名字來命名所定義的類或函數,這樣在程序中就會出現名字沖突。不僅如此,有可能我們自己定義的名字會與C++庫中的名字發生沖突。

名字沖突就是在同一個作用域中有兩個或多個同名的實體,為了解決命名沖突 ,C++中引入了命名空間,所謂命名空間就是一個可以由用戶自己定義的作用域,在不同的作用域中可以定義相同名字的變量,互不干擾,系統能夠區分它們。

C語言中避免名字沖突,只能進行起名約定

int hw_cpp_tom_num = 100;
int wd_cpp_bob_num = 200;

什么是命名空間

命名空間又稱為名字空間,是程序員命名的內存區域,程序員根據需要指定一些有名字的空間域,把一些全局實體分別存放到各個命名空間中,從而與其他全局實體分隔開。通俗的說,每個名字空間都是一個名字空間域,存放在名字空間域中的全局實體只在本空間域內有效。名字空間對全局實體加以域的限制,從而合理的解決命名沖突。

C++中定義命名空間的基本格式如下:

namespace wd
{
int val1 = 0;
char val2;
}// end of namespace wd

在聲明一個命名空間時,大括號內不僅可以存放變量,還可以存放以下類型:

變量、常量、函數、結構體、引用、類、對象、模板、命名空間等,它們都稱為實體

(1)請嘗試定義命名空間,并在命名空間中定義實體。

(2)命名空間中的實體如何使用呢?

命名空間的使用方式

命名空間一共有三種使用方式,分別是using編譯指令、作用域限定符、using聲明機制。

  1. 作用域限定符

    每次要使用某個命名空間中的實體時,都直接加上作用域限定符::,例如:

    namespace wd
    {
    int number = 10;
    void display()
    {//cout,endl都是std空間中的實體,所以都加上'std::'命名空間std::cout << "wd::display()" << std::endl;
    }
    }//end of namespace wdint main(void)
    {std::cout << "wd::number = " << wd::number << endl;wd::display();return 0;
    }

    好處:準確,只要命名空間中確實有這個實體,就能夠準確調用(訪問)

    壞處:繁瑣

  2. using編譯指令

    我們接觸的第一個C++程序基本上都是這樣的,其中std代表的是標準命名空間。

    #include <iostream>
    using namespace std; //using編譯指令int main(int argc, char * argv[]){cout << "hello,world" << endl;return 0;
    }

    其中第二行就使用了using編譯指令。如果一個名稱空間中有多個實體,使用using編譯指令,就會把該空間中的所有實體一次性引入到程序之中;對于初學者來說,如果對一個命名空間中的實體并不熟悉時,直接使用這種方式,有可能還是會造成名字沖突的問題,而且出現錯誤之后,還不好查找錯誤的原因,比如下面的程序就會報錯,當然該錯誤是人為造成的。

    #include <iostream>
    using namespace std;
    double cout()
    {
    return 1.1;
    }
    int main(void)
    {
    cout();
    return 0;
    }

    image-20240305113638435

  3. using聲明機制

using聲明機制的作用域是從using語句開始,到using所在的作用域結束。要注意,在同一作用域內用using聲明的不同的命名空間的成員不能有同名的成員,否則會發生重定義。

作用域示例

namespace A {void foo() {}int x = 10;
}void func1() {using A::foo; // 作用域開始foo();        // 正確:調用 A::foo()
} // 作用域結束(到 func1 末尾)void func2() {// foo();     // 錯誤:此處無法使用 A::foo
}

重定義示例

namespace B {void foo() {}  // 與 A::foo 同名但實現不同int x = 20;    // 與 A::x 同名
}// 全局作用域中的 using 聲明
using A::x;     // 引入 A::x
using B::x;     // 錯誤:重定義!x 已存在(來自 A)int main() {// x = 30;  // 若單獨使用一個 using 聲明,此處可訪問return 0;
}

合法作用域示例

void safe_func1() {using A::foo;foo();  // 調用 A::foo
}void safe_func2() {using B::foo;foo();  // 調用 B::foo(不同作用域,無沖突)
}
關鍵點總結
  1. 作用域限定using 聲明的作用域從聲明處開始,到當前代碼塊({})結束

  2. 沖突規則:同一作用域內不允許通過 using 引入同名標識符

  3. 隔離方案:通過函數/代碼塊劃分作用域可避免沖突

  4. using namespace 區別using 聲明精確引入單個標識符,using namespace 會污染當前作用域的所有標識符

實際開發中建議:

  • 優先在函數內局部使用 using 聲明

  • 避免在頭文件的全局作用域使用 using

  • 對頻繁使用的標識符,使用 namespace alias(如 namespace fs = std::filesystem;

#include <iostream>
using std::cout;
using std::endl;
namespace wd
{
int number = 10;
void display()
{
cout << "wd::display()" << endl;
}
}//end of namespace wd
using wd::number;
using wd::display;
int main(void)
{cout << "wd::number = " << number << endl;wd::display();return 0;
}

在這三種方式之中,我們推薦使用的就是第三種,需要哪個實體的時候就引入到程序中,不需要的實體就不引入,盡可能減小犯錯誤的概率。

image-20240305113925045

命名空間的嵌套使用

類似于文件夾下還可以建立文件夾,命名空間中還可以定義命名空間。那么內層命名空間中的實體如何訪問呢?嘗試一下

image-20240305114217487

image-20240305114537247

匿名命名空間

命名空間還可以不定義名字,不定義名字的命名空間稱為匿名命名空間(簡稱匿名空間),其定義方式如下:

namespace {
int val1 = 10;
void func();
}//end of anonymous namespace

image-20240305115202613

使用匿名空間中實體時,可以直接使用,也可以加上作用域限定符(沒有空間名),但是如果匿名空間中定義了和全局位置中同名的實體,會有沖突,即使使用::作用域限定符也無法訪問到匿名空間中重名的實體,只能訪問到全局的實體。

在C++代碼中可以直接使用一些C語言的函數,就是通過匿名空間實現(體現了C++對C的兼容性),在本文件使用匿名命名空間的實體時不必用命名空間限定。

image-20240305120025058

image-20240305120642759

printf本身可以直接用,和C語言中的效果一致。但是經過匿名空間改寫后,效果不一樣了 —— 不要隨意改寫

匿名空間注意事項:

(1)匿名空間不要定義與全局空間中同名的實體;

(2)匿名空間中支持改寫兼容C語言的函數,但是最好不要改寫;

(3)匿名空間中的實體不能跨模塊調用。

補充:匿名空間和有名空間(具名空間)統稱為命名空間(名稱空間)。

跨模塊調用問題

一個.c/.cc/*.cpp的文件可以稱為一個模塊。

(1)全局變量和函數是可以跨模塊調用的

externA.cc

image-20240305144421267

externB.cc

image-20240305144326193

對externA.cc和externB.cc聯合編譯,實現跨模塊調用

(2)有名命名空間中的實體可以跨模塊調用

image-20240305181047048

命名空間中的實體跨模塊調用時,要在新的源文件中再次定義同名的命名空間,進行聯合編譯時,這兩次定義被認為是同一個命名空間。

使用規則:如果要同時從全局位置和命名空間中外部引入實體,要么讓它們不要重名,要么在使用時采取作用域限定的方式。

using wd2 :: num 放在test2外面就發生沖突,使用using namespace wd2 也會發生沖突,看似不在一個作用域也會沖突,所以就用上面的解決辦法。

(3)靜態變量和函數只能在本模塊內部使用

image-20240305151609213

(4)匿名空間的實體只能在本模塊內部使用

匿名空間中的實體只能在本文件的作用域內有效,它的作用域是從匿名命名空間聲明開始到本文件結束。

image-20240305153745838

補充:extern外部引入的方式適合管理較小的代碼組織,用什么就引入什么,但是如果跨模塊調用的關系不清晰,很容易出錯;

include頭文件的方式在代碼組織上更清晰,但是會一次引入全部內容,相較而言效率比較低。

命名空間可以多次定義

函數可以聲明多次,但是只能定義一次;命名空間可以多次定義。

image-20240305152144711

在同一個源文件中可以多次定義同名的命名空間,被認為是同一個命名空間,所以不能進行重復定義。

image-20240305152606533

在命名空間中可以聲明實體、定義實體,但是不能使用實體。使用命名空間中的實體一定在命名空間之外,可以理解為命名空間只是用來存放實體。

總結

命名空間的作用:

  1. 避免命名沖突:命名空間提供了一種將全局作用域劃分成更小的作用域的機制,用于避免不同的代碼中可能發生的命名沖突問題;

  2. 組織代碼:將相關的實體放到同一個命名空間;

  3. 版本控制:不同版本的代碼放到不同的命名空間中;

    總之,需要用到代碼分隔的情況就可以考慮使用命名空間。

還有一個隱藏的好處:聲明主權。

下面引用當前流行的命名空間使用指導原則:

  1. 提倡在已命名的名稱空間中定義變量,而不是直接定義外部全局變量或者靜態全局變量。

  2. 如果開發了一個函數庫或者類庫,提倡將其放在一個命名空間中。

  3. 對于using 聲明,首先將其作用域設置為局部而不是全局。

  4. 不要在頭文件中使用using編譯指令,這樣,使得可用名稱變得模糊,容易出現二義性。

  5. 包含頭文件的順序可能會影響程序的行為,如果非要使用using編譯指令,建議放在所有#include預編譯指令后。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/71995.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/71995.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/71995.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Redux 和 MobX 高頻面試題

Redux 和 MobX 是 React 生態中的兩大狀態管理方案&#xff0c;在面試中常涉及 原理、使用方式、對比、最佳實踐 等方面。以下是 高頻面試題 詳細答案&#xff0c;助你輕松應對面試&#xff01;&#x1f680; &#x1f525; Redux 部分 1. Redux 是什么&#xff1f;為什么需要…

Excel 保護工作簿:它能解決哪些問題?如何正確使用?

在日常辦公中&#xff0c;Excel 表格常常涉及多人協作、重要數據保護&#xff0c;甚至是避免誤操作的情況。這時候&#xff0c;“保護工作簿”功能就能派上用場。它能有效防止他人修改表結構、刪除工作表&#xff0c;甚至可以設置密碼&#xff0c;確保數據的完整性和安全性。今…

Android Retrofit 框架注解定義與解析模塊深度剖析(一)

一、引言 在現代 Android 和 Java 開發中&#xff0c;網絡請求是不可或缺的一部分。Retrofit 作為 Square 公司開源的一款強大的類型安全的 HTTP 客戶端&#xff0c;憑借其簡潔易用的 API 和高效的性能&#xff0c;在開發者社區中廣受歡迎。Retrofit 的核心特性之一便是通過注…

C# Enumerable類 之 數據分組

總目錄 前言 在 C# 中&#xff0c;System.Linq.Enumerable 類是 LINQ&#xff08;Language Integrated Query&#xff09;的核心組成部分&#xff0c;它提供了一系列靜態方法&#xff0c;用于操作實現了 IEnumerable 接口的集合。通過這些方法&#xff0c;我們可以輕松地對集合…

推理模型對SQL理解能力的評測:DeepSeek r1、GPT-4o、Kimi k1.5和Claude 3.7 Sonnet

引言 隨著大型語言模型&#xff08;LLMs&#xff09;在技術領域的應用日益廣泛&#xff0c;評估這些模型在特定技術任務上的能力變得越來越重要。本研究聚焦于四款領先的推理模型——DeepSeek r1、GPT-4o、Kimi k1.5和Claude 3.7 Sonnet在SQL理解與分析方面的能力&#xff0c;…

IDEA接入阿里云百煉中免費的通義千問[2025版]

安裝deepseek 上一篇文章IDEA安裝deepseek最新教程2025中說明了怎么用idea安裝codeGPT插件&#xff0c;并接入DeepSeek&#xff0c;無奈接入的官方api已經不能使用了&#xff0c;所以我們嘗試從其他地方接入 阿里云百煉https://bailian.console.aliyun.com/ 阿里云百煉?是阿…

實施一套先進的智能攝像頭服務系統。

一、項目背景 隨著物聯網、人工智能和大數據技術的飛速發展&#xff0c;智能攝像頭已成為家庭、企業以及公共安全領域的重要設備。其便捷、高效、智能的特點&#xff0c;使得市場需求日益增長。為了滿足用戶對智能監控的多樣化需求&#xff0c;提供更加全面、可靠的監控服務&a…

linux自啟動服務

在Linux環境中&#xff0c;systemd是一個系統和服務管理器&#xff0c;它為每個服務使用.service文件進行配置。systemctl是用于控制系統服務的主要工具。本文將詳細介紹如何使用systemctl來管理vsftpd服務&#xff0c;以及如何設置服務自啟動。 使用Systemd設置自啟動服務 創…

010-Catch2

Catch2 一、框架簡介 Catch2 是一個基于 C 的現代化單元測試框架&#xff0c;支持 TDD&#xff08;測試驅動開發&#xff09;和 BDD&#xff08;行為驅動開發&#xff09;模式。其核心優勢在于&#xff1a; 單頭文件設計&#xff1a;v2.x 版本僅需包含 catch.hpp 即可使用自然…

數字人分身開發指南:從概念到實戰

一、什么是數字人分身&#xff1f; 想象一下&#xff0c;在電腦或手機屏幕里&#xff0c;一個能跟你聊天、回答問題&#xff0c;甚至還能做表情的虛擬角色。這就是數字人分身&#xff0c;它用上了人工智能技術&#xff0c;讓機器也能像人一樣交流。無論是在線客服、網絡主播還…

Pixelmator Pro for Mac 專業圖像處理軟件【媲美PS的修圖】

介紹 Pixelmator Pro&#xff0c;是一款非常強大、美觀且易于使用的圖像編輯器&#xff0c;專為 Mac 設計。采用單窗口界面、基于機器學習的智能圖像編輯、自動水平檢測&#xff0c;智能快速選擇及更好的修復工具等功能優點。許多非破壞性的專業編輯工具可讓您進行最佳的照片處…

LiveGBS流媒體平臺GB/T28181常見問題-視頻流安全控制HTTP接口鑒權勾選流地址鑒權后401Unauthorized如何播放調用接口流地址校驗

LiveGBS流媒體平臺GB/T28181常見問題頻流安全控制HTTP接口鑒權勾選流地址鑒權后401Unauthorized如何播放調用接口流地址校驗&#xff1f; 1、安全控制1.1、HTTP接口鑒權1.2、流地址鑒權 2、401 Unauthorized2.1、攜帶token調用接口2.1.1、獲取鑒權token2.1.2、調用其它接口2.1.…

C++設計模式-抽象工廠模式:從原理、適用場景、使用方法,常見問題和解決方案深度解析

一、模式基本概念 1.1 定義與核心思想 抽象工廠模式&#xff08;Abstract Factory Pattern&#xff09;是創建型設計模式的集大成者&#xff0c;它通過提供統一的接口來創建多個相互關聯或依賴的對象族&#xff0c;而無需指定具體類。其核心思想體現在兩個維度&#xff1a; …

【prompt實戰】知乎問題解答專家

本文原創作者&#xff1a;姚瑞南 AI-agent 大模型運營專家&#xff0c;先后任職于美團、獵聘等中大廠AI訓練專家和智能運營專家崗&#xff1b;多年人工智能行業智能產品運營及大模型落地經驗&#xff0c;擁有AI外呼方向國家專利與PMP項目管理證書。&#xff08;轉載需經授權&am…

數據結構第八節:紅黑樹(初階)

【本節要點】 紅黑樹概念紅黑樹性質紅黑樹結點定義紅黑樹結構紅黑樹插入操作的分析 一、紅黑樹的概念與性質 1.1 紅黑樹的概念 紅黑樹 &#xff0c;是一種 二叉搜索樹 &#xff0c;但 在每個結點上增加一個存儲位表示結點的顏色&#xff0c;可以是 Red和 Black 。 通過對 任何…

Spring Boot3.3.X整合Mybatis-Plus

前提說明&#xff1a; 項目的springboot版本為&#xff1a;3.3.2 需要整合的mybatis-plus版本&#xff1a;3.5.7 廢話不多說&#xff0c;開始造吧 1.準備好數據庫和表 2.配置全局文件application.properties或者是application.yml&#xff08;配置mapper的映射文件路徑&am…

可視化圖解算法:鏈表指定區間反轉

1. 題目 描述 給你單鏈表的頭指針 head 和兩個整數 left 和 right &#xff0c;其中 left < right 。請你反轉從位置 left 到位置 right 的鏈表節點&#xff0c;返回 反轉后的鏈表 。 示例1 輸入&#xff1a; 輸入&#xff1a;head [1,2,3,4,5], left 2, right 4 輸…

?SQL-遞歸CTE

&#x1f4d6; SQL魔法課堂&#xff1a;CTE「時間折疊術」全解 &#x1f3a9; 第一章&#xff1a;什么是CTE&#xff1f; CTE&#xff08;Common Table Expression&#xff09; 就像 SQL 里的「臨時筆記本」&#x1f4d2;&#xff1a; WITH 臨時筆記本 AS ( SELECT ... FRO…

Cursor 新手入門使用教程

一、Cursor 是什么&#xff1f; Cursor 是一個集成了 GPT-4、Claude 3.5 等先進 LLM&#xff08;大語言模型&#xff09;的類 VSCode 編譯器&#xff0c;可以理解為在 VSCode 中集成了 AI 輔助編程助手。從界面布局來看&#xff0c;Cursor 與 VSCode 基本一致&#xff0c;且使…

如何在Spring Boot中配置和使用MyBatis-Plus

在當今的Java開發中&#xff0c;Spring Boot已經成為了一個非常流行的框架&#xff0c;而MyBatis-Plus則是一個強大的ORM框架&#xff0c;為開發人員提供了更簡便的數據庫操作方式。很多開發者都在使用Spring Boot和MyBatis-Plus的組合來快速構建高效的應用。今天就來聊聊如何在…