C ++: Namespaces - วิธีใช้ในไฟล์ส่วนหัวและไฟล์ต้นฉบับอย่างถูกต้อง?


90

พิจารณาไฟล์ต้นฉบับสองไฟล์: ไฟล์ประกาศอินเตอร์เฟส ( *.hหรือ*.hpp) และไฟล์การนำไปใช้งาน ( *.cpp)

ให้*.hไฟล์เป็นดังนี้:

namespace MyNamespace {
  class MyClass {
  public:
    int foo();
  };
}

ฉันได้เห็นแนวทางปฏิบัติสองประการในการใช้เนมสเปซในไฟล์ต้นฉบับ:

*.cpp แสดงการปฏิบัติ # 1:

#include "MyClass.h"
using namespace MyNamespace;

int MyClass::foo() { ... }

*.cpp แสดงการปฏิบัติ # 2:

#include "MyClass.h"
namespace MyNamespace {

  int MyClass::foo() { ... }

}

คำถามของฉัน:มีความแตกต่างระหว่างการปฏิบัติทั้งสองนี้และถือว่าดีกว่าอีกแบบหนึ่งหรือไม่?


30
นอกจากนี้ยังมีตัวเลือกที่ 3: int MyNamespace::MyClass::foo() ...เพียงแค่เราชื่อเต็มเช่น
Benjamin Bannier

1
อาจซ้ำกันได้: stackoverflow.com/questions/7789163/…
David

@ เดฟไม่ซ้ำกัน. คำถามเหล่านี้ช่วยเสริมกันและกัน แนะนำให้เพิ่มลิงก์ที่ Dave ให้ไว้ว่า "Read also ... " สำหรับคำถามนี้ คำถามของฉันจะช่วยให้มือใหม่เลือกรูปแบบที่ถูกต้อง
nickolay

อาจซ้ำกันได้: stackoverflow.com/questions/8210935/…
Firedragon

คำตอบ:


65

จากมุมมองความสามารถในการอ่านรหัสมันน่าจะดีกว่าในความคิดของฉันที่จะใช้วิธี # 2 ด้วยเหตุผลนี้:

คุณสามารถเป็นusingหลายเนมสเปซได้พร้อมกันและอ็อบเจ็กต์หรือฟังก์ชันใด ๆ ที่เขียนไว้ด้านล่างบรรทัดนั้นสามารถเป็นของเนมสเปซใดก็ได้ (ยกเว้นความขัดแย้งในการตั้งชื่อ) การห่อไฟล์ทั้งไฟล์ในnamespaceบล็อกมีความชัดเจนมากกว่าและช่วยให้คุณสามารถประกาศฟังก์ชันและตัวแปรใหม่ที่เป็นของเนมสเปซนั้นภายในไฟล์. cpp ได้เช่นกัน


คำถามที่ Dave เชื่อมโยงในความคิดเห็นของเขากับคำถามของคุณยังสรุปประเด็นสำคัญบางประการในความแตกต่าง (ถ้ามี) ระหว่างสองวิธีที่คุณกำลังดูอยู่
Dan F

พวกฉันไม่รู้จริงๆว่าจะเลือกคำตอบของใคร พวกเขามีจุดตัดและเสริมซึ่งกันและกัน
nickolay

เพียงแสดงความคิดเห็นเพื่อรับทราบว่า IDE บางอย่างเช่น CLion จะตรวจจับการใช้งานได้ก็ต่อเมื่อคุณใช้ option / practice # 2
pedrostanaka

@PedroTanaka ยังเป็นแบบนี้อยู่หรือเปล่า? ฉันไม่ได้สังเกตเห็นปัญหาดังกล่าว
John McFarlane

@JMcF ฉันไม่ได้ตรวจสอบตั้งแต่ตอนที่เผยแพร่ความคิดเห็น ในเวอร์ชันแรกของ Clion เกิดปัญหาขึ้น
pedrostanaka

52

ที่ชัดเจนที่สุดคือตัวเลือกที่คุณไม่ได้แสดง:

int MyNamespace::MyClass::foo()
{
    //  ...
}

นอกจากนี้ยังมีรายละเอียดมาก มากเกินไปสำหรับคนส่วนใหญ่ เนื่องจากusing namespaceเป็นใบตอบรับสำหรับความขัดแย้งของชื่ออย่างน้อยก็ในประสบการณ์ของฉันและควรหลีกเลี่ยงยกเว้นในขอบเขตและสถานที่ที่ จำกัด มากฉันมักใช้ # 2 ของคุณ


4
ขอบคุณมาก เราได้ร่วมกันสร้างหน้าคำถามที่พบบ่อยสำหรับผู้ใช้เนมสเปซ :)
nickolay

2
พวกฉันไม่รู้จริงๆว่าจะเลือกคำตอบของใคร พวกเขามีจุดตัดและเสริมซึ่งกันและกัน
nickolay

10

มีความแตกต่างระหว่างการปฏิบัติทั้งสองนี้หรือไม่

ใช่. # 1 และ # 2 เป็นตัวอย่างของการใช้คำสั่งและคำจำกัดความของเนมสเปซตามลำดับ ในกรณีนี้มีผลเหมือนกัน แต่มีผลกระทบอื่น ๆ ตัวอย่างเช่นหากคุณแนะนำตัวระบุใหม่ควบคู่ไปMyClass::fooด้วยก็จะมีขอบเขตที่แตกต่างกัน:

# 1:

using namespace MyNamespace;
int x;  // defines ::x

# 2:

namespace MyNamespace {
  int x;  // defines MyNamespace::x
}

ถือว่าดีกว่าอีกอันไหม

# 1 ข้อดี: เล็กน้อยมากขึ้น; ยากที่จะแนะนำบางสิ่งบางอย่างเข้าไปโดยบังเอิญMyNamespaceโดยไม่เจตนาโดยไม่เจตนา จุดด้อย: อาจดึงตัวระบุที่มีอยู่โดยไม่ได้ตั้งใจ

# 2 จุดเด่น: MyNamespaceชัดเจนมากขึ้นว่าคำจำกัดความของตัวระบุที่มีอยู่และการประกาศของตัวระบุใหม่ทั้งสองเป็นของ จุดด้อย: ง่ายกว่าในการแนะนำตัวระบุโดยไม่ได้ตั้งใจMyNamespaceง่ายต่อการไม่ได้ตั้งใจที่จะแนะนำตัวระบุ

คำวิจารณ์ของทั้ง # 1 และ # 2 คือพวกเขาอ้างถึงเนมสเปซทั้งหมดเมื่อคุณอาจสนใจเฉพาะคำจำกัดความของสมาชิกของ MyNamespace::MyClass . นี่เป็นงานหนักและสื่อสารเจตนาได้ไม่ดี

ทางเลือกที่เป็นไปได้สำหรับ # 1 คือการประกาศใช้ซึ่งรวมเฉพาะตัวระบุที่คุณสนใจ:

#include "MyClass.h"
using MyNamespace::MyClass;

int MyClass::foo() { ... }

5

ฉันต้องการเพิ่มด้วยว่าหากคุณตัดสินใจด้วยเหตุผลบางประการในการใช้ความเชี่ยวชาญเทมเพลตในไฟล์ cpp และพึ่งพาusing namespaceคุณจะพบปัญหาต่อไปนี้:

// .h file
namespace someNameSpace
{
  template<typename T>
    class Demo
    {
      void foo();
    };
}

// .cpp file
using namespace someNameSpace;

template<typename T>
void Demo<T>::foo(){}

// this will produce
// error: specialization of 'template<class T> void someNameSpace::Demo<T>::foo()' in different namespace [-fpermissive]
template<>
void Demo<int>::foo(){}

มิฉะนั้นหากคุณใช้วิธี # 2 จะไม่เป็นไร


0

ฉันต้องการเพิ่มอีกหนึ่งวิธีโดยใช้การประกาศ :

#include "MyClass.h"
using MyNamespace::MyClass;

int MyClass::foo() { ... }

วิธีนี้ช่วยให้คุณประหยัดเวลาในการพิมพ์ชื่อเนมสเปซหลาย ๆ ครั้งหากคลาสมีหลายฟังก์ชัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.