C++名稱空間在多檔案程式設計中的具體用法

2020-07-16 10:05:22
《C++名稱空間》一節講到,C++ 引入名稱空間是為了避免合作開發專案時產生命名衝突,例如:
#include <iostream>
namespace Li {  //小李的變數定義
    class Student {
    public:
        void display(){
            std::cout << "Li::display" << std::endl;
        }
    };
}
namespace Han {  //小韓的變數定義
    class Student {
    public:
        void display() {
            std::cout << "Han::display" << std::endl;
        }
    };
}
int main() {
    Li::Student stu1;
    stu1.display();

    Han::Student stu2;
    stu2.display();
    return 0;
}
程式執行結果為:

Li::display
Han::display

如上所示,小李與小韓各自定義了以自己姓氏為名的名稱空間,此時再將他們各自定義的 Student 類放在一起編譯就不會有任何問題。

那麼當進行多檔案程式設計時,名稱空間又該如何使用呢?一個專案的多個檔案中可以使用同一個名稱空間嗎?接下來就對這些疑問做一一解答。

《C++多檔案程式設計是什麼》一節講到,當進行多檔案程式設計時,通常是將宣告部分(例如變數、函數和類等)劃分到 .h 檔案中,將實現部分劃分到 .cpp 檔案中。在此基礎上,如果要給變數、函數或者類指定名稱空間,則該命令空間應至少包含它們的宣告部分。所以當進行多檔案程式設計時,名稱空間常位於 .h 標頭檔案中。

舉個例子,如下是對之前程式做的合理劃分:
//student_li.h
#ifndef _STUDENT_LI_H
#define _STUDENT_LI_H
namespace Li {  //小李的變數定義
    class Student {
    public:
        void display();
    };
}
#endif

//student_li.cpp
#include "student_li.h"
#include <iostream>
void Li::Student::display() {
    std::cout << "Li::display" << std::endl;
}

//student_han.h
#ifndef _STUDENT_HAN_H
#define _STUDENT_HAN_H
namespace Han {  //小韓的變數定義
    class Student {
    public:
        void display();
    };
}
#endif

//student_han.cpp
#include "student_han.h"
#include <iostream>
void Han::Student::display() {
    std::cout << "han::display" << std::endl;
}

//main.cpp
#include <iostream>
#include "student_han.h"
#include "student_li.h"
int main() {
    Li::Student stu1;
    stu1.display();
    Han::Student stu2;
    stu2.display();
    return 0;
}
專案執行結果為:

Li::display
han::display

注意,當類的宣告位於指定的名稱空間中時,如果要在類的外部實現其成員方法,需同時註明所在名稱空間名和類名(例如本專案中的 Li::Student::display() )。

上面的程式範例中,不同的標頭檔案中使用的是不同的名稱空間,除此之外,不同標頭檔案中也可以使用名稱相同的名稱空間,但前提是位於該名稱空間中的成員必須保證互不相同。

舉個例子:
//demo1.h
#ifndef _DEMO1_H
#define _DEMO1_H
#include<iostream>
namespace demo {
    void display() {
        std::cout << "demo1::display" << std::endl;
    }
    int num=20;
}
#endif

//demo2.h
#ifndef _DEMO2_H
#define _DEMO2_H
#include <iostream>
namespace demo {
    void display(int a) {
        std::cout << "demo2::display" << std::endl;
    }
    //int num; 因為 demo1.h 中已經宣告有同名的變數,取消註釋會造成重定義錯誤
}
#endif

//main.cpp
#include <iostream>
#include "demo1.h"
#include "demo2.h"
int main() {
    demo::display();
    demo::display(2);
    std::cout << demo::num << std::endl;
    return 0;
}
專案執行結果為:

demo1::display
demo2::display
20

注意,本例中 display() 函數的實現也位於 .h 檔案中,僅僅是為了演示方便,讀者可自行將該函數的宣告和定義進行合理劃分。

可以看到,demo1.h 和 demo2.h 檔案中都定義有 demo 名稱空間,當這 2 個標頭檔案被引入到 main.cpp 檔案中時,意味著 demo 空間中同時包含 display()、display(int n) 以及 num 這 3 個成員。也就是說,分散在不同檔案中的同名名稱空間會合併為一個。

再次強調,雖然同一專案的不同檔案中可以定義相同的名稱空間,但必須保證空間中的成員互不相同,否則編譯器會報“重定義”錯誤。注意,這裡的 display() 和 display(int n) 並不會造成重定義,它們互為過載函數。