2013-01-16 27 views
29

Thực hành tốt hay không là sử dụng không gian tên làm lớp tĩnh? Ví dụ:Sử dụng một không gian tên thay cho một lớp tĩnh trong C++?

namespace MyStaticFunctions { 
    void doSomething(); 
} 

Versus:

class MyStaticFunctions { 
    static void doSomething(); 
} 
+0

tôi thích "extern" bởi vì chỉ có C + + có thể làm điều đó trong OOP;) Cũng cho C hoặc Objective C tương thích. – 9dan

+3

* "Thực hành tốt hay không tốt để sử dụng không gian tên như một lớp tĩnh" * - Thực ra nó là thực hành tốt hơn nhiều so với tùy chọn thứ hai của bạn. Cái sau chỉ được ưa thích (hay đúng hơn là cần thiết) nếu bạn cần một không gian tên mẫu * "*" hoặc muốn tạo một không gian tên toàn bộ một người bạn của một lớp khác (mặc dù điều đó cũng có thể nghi ngờ). –

Trả lời

34

Không có thứ như "lớp tĩnh" trong C++, do đó, từ điểm C++, bạn không sử dụng nó "làm lớp tĩnh", bạn đang sử dụng nó "làm không gian tên". Nó chắc chắn chấp nhận thực hành để sử dụng không gian tên để nhóm chức năng với nhau.

Tùy thuộc vào bạn, bạn muốn các nhóm như thế nào. Nó không phải bất thường đối với các thư viện C++ để sử dụng một không gian tên duy nhất cho toàn bộ giao diện công cộng. Điều đó có thể gây ngạc nhiên cho một người quen với Java (nói), nơi các lớp thường được sử dụng để nhóm các số phương pháp tĩnh lại với nhau. Vì C++ đã ở đây đầu tiên, bạn có thể nói rằng Java đang sử dụng các lớp như các không gian tên.

Vì vậy, trong C++ bạn không có xu hướng xem các lớp tương tự như java.util.Collections hoặc java.lang.Math, đầy đủ các thành viên tĩnh. Nếu bạn muốn các nhóm hàm giống như vậy trong C++, hãy sử dụng các không gian tên.

Trường hợp ngoại lệ (không phải lúc nào cũng có trường hợp đặc biệt trong C++?) Là các kiểu đặc điểm như std::numeric_limits<T>, trong đó tham số mẫu làm cho lớp làm điều gì đó mà không gian tên không thể thực hiện. Bạn có thể xác định không gian tên numeric_limits chứa các mẫu chức năng max<T>(), min<T>() v.v. nhưng không tốt. Thứ nhất, nó nhóm các thứ hơi khác nhau, loại T xuất hiện "hạ thấp phân cấp". Thứ hai, nó không làm mọi thứ mà một kiểu đặc điểm, bởi vì không có thứ gì như một "mẫu đối tượng" cho phép bạn định nghĩa một giá trị numeric_limits::digits<T>.

Tôi không biết C# cũng đủ để nhận xét về cách sử dụng thực tế của các lớp tĩnh ở đó, nhưng AFAIK nó chỉ là một lớp hạn chế không có thành viên không tĩnh, vì vậy nó tương tự như các lớp Java.

+1

+1 Một trường hợp khác mà lớp * "tĩnh" * có thể có ích nếu bạn muốn tạo một không gian tên toàn bộ một người bạn của một lớp khác (mặc dù thiết kế đó có thể có vấn đề ngay từ đầu, nhưng đôi khi có thể dễ dàng). –

+4

Một trường hợp khác _namespaces_ là tốt hơn. bạn có thể sử dụng 'using namespace MyStaticFunctions' nếu bạn định sử dụng nhiều funtctions này trong hàm – balki

4

Nó phụ thuộc.

Phương pháp có liên quan logic đến một lớp học không? Nếu vậy, hãy biến nó thành một thành viên, nếu không thì hãy đặt nó vào một không gian tên.

Chức năng, chúng giống nhau, nhưng có nhiều mã hơn hàm, phải không? Ví dụ, hãy xem xét một phương pháp mà trả về tên của lớp:

struct MyClass 
{ 
    static std::string getName() { return "MyClass"; } 
} 

Bạn rõ ràng có thể đặt phương pháp bên ngoài, trong một namespace, và nhận được kết quả tương tự, nhưng nó một cách logic thuộc về lớp.

+1

"Có liên quan đến một lớp học" có nghĩa là gì? –

+0

@AndyT: vâng, logic của nó liên quan chặt chẽ đến logic của lớp. –

21

Trong C++, bạn thực sự được khuyến khích ở cấp độ ngôn ngữ sử dụng namespace thay vì class chỉ chứa static phương pháp vì tra cứu của Koenig (còn gọi là Truy vấn phụ thuộc đối số).

Ví dụ:

namespace geometry { 
    struct Point { int x, y; }; 

    double distance_from_center(Point const& p) { 
     return sqrt(p.x * p.x + p.y + p.y); 
    } 
} // namespace geometry 

int main() { 
    geometry::Point const p{3, 4}; // must qualify 

    std::cout << distance_from_center(p) << "\n"; // not qualified 
} 

Nếu distance_from_center được viết như một phương pháp static trong một class, thì bạn cần phải hội đủ điều kiện rõ ràng nó mỗi lần.

+1

Tôi chưa bao giờ biết điều này! tuy nhiên rõ ràng sẽ làm cho nó dễ đọc hơn – balki

+1

@balki: dễ đọc hơn hoặc lộn xộn hơn? Nó luôn luôn là một sự cân bằng tốt. Nó có thể là một chút chói cho Java/C# guys, nhưng nó thành ngữ trong C + + vì vậy không có vấn đề. Hơn nữa, trong mã chung (mẫu), nó dễ dàng hơn nhiều. –

8

Đó là một câu hỏi hóc búa và thú vị cho cá nhân tôi, vì vậy quyết định chia sẻ thiển ý của tôi

Xét sự khác biệt giữa lớp "tĩnh" (chỉ các thành viên tĩnh) và không gian tên:

  1. một namespace có thể được phân tán trên nhiều tệp: linh hoạt bổ sung nhưng nên được sử dụng cẩn thận.
  2. một namespace cung cấp luận cứ tra cứu phụ thuộc (see Matthieu M. answer): hữu ích trong những tình huống cụ thể
  3. một lớp "tĩnh" có thể có bổ truy cập và có thể hình thành một hệ thống cấp bậc: Tôi nghĩ rằng các thành viên tin khai báo trong giao diện lớp và hiển thị cho khách hàng của nó là một Tính năng C++ đã được quyết định nhiều hơn bởi các lý do kỹ thuật, không logic. Tôi không thấy bất kỳ lợi ích của các thành viên tĩnh tư nhân. Thành viên được bảo vệ cho phân cấp "tĩnh"? Chưa bao giờ thấy bất kỳ.
  4. một lớp "tĩnh" có thể là một "mẫu", ngoài các thành viên mẫu: xem Steve Jessop's answer cho một ví dụ tuyệt vời từ STL

Từ quan điểm duy trì quan điểm, đôi khi bạn quyết định để thực hiện một lớp "tĩnh "(như một singleton), nhưng sau đó yêu cầu đã thay đổi và bạn cần nhiều phiên bản. Lớp "tĩnh" sẽ dễ chuyển đổi hơn không gian tên.

Và, cuối cùng, để trả lời câu hỏi của bạn:

nếu bạn không cần các tính năng đặc biệt của lớp "tĩnh" hay không gian tên, sử dụng những gì bạn thích hơn :)

+0

Bây giờ tôi tuyệt vọng muốn nghĩ đến việc sử dụng cho một thành viên được bảo vệ trong một lớp chỉ có các thành viên tĩnh. Có lẽ một số loại tình huống giống như CRTP, nơi một lớp tự nhiên có một mối quan hệ đặc biệt với các lớp học có nguồn gốc của nó? –

Các vấn đề liên quan