Hãy xem xét giải pháp của Matt Price .
- Trong C ++, một "lớp tĩnh" không có nghĩa. Thứ gần nhất là một lớp chỉ có các phương thức tĩnh và các thành viên.
- Sử dụng phương pháp tĩnh sẽ chỉ giới hạn bạn.
Những gì bạn muốn là, được thể hiện trong ngữ nghĩa C ++, để đặt hàm của bạn (vì nó là một hàm) trong một không gian tên.
Chỉnh sửa 2011-11-11
Không có "lớp tĩnh" trong C ++. Khái niệm gần nhất sẽ là một lớp chỉ có các phương thức tĩnh. Ví dụ:
// header
class MyClass
{
public :
static void myMethod() ;
} ;
// source
void MyClass::myMethod()
{
// etc.
}
Nhưng bạn phải nhớ rằng "các lớp tĩnh" là các hack trong loại ngôn ngữ giống như Java (ví dụ C #) không thể có các hàm không phải là thành viên, vì vậy chúng phải di chuyển chúng vào bên trong các lớp như các phương thức tĩnh.
Trong C ++, điều bạn thực sự muốn là một hàm không phải là thành viên mà bạn sẽ khai báo trong một không gian tên:
// header
namespace MyNamespace
{
void myMethod() ;
}
// source
namespace MyNamespace
{
void myMethod()
{
// etc.
}
}
Tại sao vậy?
Trong C ++, không gian tên mạnh hơn các lớp cho mẫu "Phương thức tĩnh Java", bởi vì:
- phương thức tĩnh có quyền truy cập vào các biểu tượng riêng
- phương thức tĩnh riêng vẫn có thể nhìn thấy (nếu không thể truy cập được) đối với mọi người, điều này vi phạm phần nào sự đóng gói
- phương thức tĩnh không thể được khai báo
- Các phương thức tĩnh không thể bị quá tải bởi người dùng lớp mà không sửa đổi tiêu đề thư viện
- không có gì có thể được thực hiện bằng một phương thức tĩnh không thể được thực hiện tốt hơn một hàm không phải là thành viên (có thể là bạn) trong cùng một không gian tên
- không gian tên có ngữ nghĩa riêng của chúng (chúng có thể được kết hợp, chúng có thể ẩn danh, v.v.)
- Vân vân.
Kết luận: Không sao chép / dán mẫu của Java / C # trong C ++. Trong Java / C #, mẫu là bắt buộc. Nhưng trong C ++, đó là phong cách xấu.
Chỉnh sửa 2010-06-10
Có một đối số có lợi cho phương thức tĩnh bởi vì đôi khi, người ta cần sử dụng một biến thành viên riêng tĩnh.
Tôi không đồng ý một chút, như hiển thị dưới đây:
Giải pháp "Thành viên riêng tĩnh"
// HPP
class Foo
{
public :
void barA() ;
private :
void barB() ;
static std::string myGlobal ;
} ;
Đầu tiên, myGlobal được gọi là myGlobal vì nó vẫn là biến riêng tư toàn cầu. Nhìn vào nguồn CPP sẽ làm rõ rằng:
// CPP
std::string Foo::myGlobal ; // You MUST declare it in a CPP
void Foo::barA()
{
// I can access Foo::myGlobal
}
void Foo::barB()
{
// I can access Foo::myGlobal, too
}
void barC()
{
// I CAN'T access Foo::myGlobal !!!
}
Ngay từ cái nhìn đầu tiên, thực tế là thanh chức năng miễn phíC không thể truy cập Foo :: myGlobal có vẻ là một điều tốt từ quan điểm đóng gói ... Thật tuyệt vì ai đó nhìn vào HPP sẽ không thể (trừ khi dùng đến phá hoại) để truy cập Foo :: myGlobal.
Nhưng nếu bạn nhìn kỹ, bạn sẽ thấy đó là một sai lầm khổng lồ: Không chỉ biến riêng tư của bạn vẫn phải được khai báo trong HPP (và do đó, hiển thị với tất cả mọi người, mặc dù là riêng tư), nhưng bạn phải khai báo trong cùng một chức năng HPP, tất cả (như trong TẤT CẢ) sẽ được phép truy cập vào nó !!!
Vì vậy, sử dụng một thành viên tĩnh riêng giống như đi ra ngoài trong hình khỏa thân với danh sách những người yêu bạn xăm trên da của bạn: Không ai được phép chạm vào, nhưng mọi người đều có thể nhìn trộm. Và phần thưởng: Mọi người đều có thể có tên của những người được ủy quyền để chơi với những người bạn của bạn.
private
thực sự ... :-D
Giải pháp "Không gian tên ẩn danh"
Không gian tên ẩn danh sẽ có lợi thế làm cho mọi thứ riêng tư thực sự riêng tư.
Đầu tiên, tiêu đề HPP
// HPP
namespace Foo
{
void barA() ;
}
Chỉ cần chắc chắn rằng bạn nhận xét: Không có tuyên bố vô dụng của barB cũng như myGlobal. Điều đó có nghĩa là không ai đọc tiêu đề biết những gì ẩn sau barA.
Sau đó, CPP:
// CPP
namespace Foo
{
namespace
{
std::string myGlobal ;
void Foo::barB()
{
// I can access Foo::myGlobal
}
}
void barA()
{
// I can access myGlobal, too
}
}
void barC()
{
// I STILL CAN'T access myGlobal !!!
}
Như bạn có thể thấy, giống như khai báo "lớp tĩnh", fooA và fooB vẫn có thể truy cập myGlobal. Nhưng không ai khác có thể. Và không ai khác ngoài CPP này biết fooB và myGlobal thậm chí còn tồn tại!
Không giống như "lớp tĩnh" đi trên khỏa thân với sổ địa chỉ của cô được xăm trên da, không gian tên "ẩn danh" được trang bị đầy đủ , có vẻ như AFAIK được gói gọn hơn.
Thật sự nó có ảnh hưởng sao?
Trừ khi những người sử dụng mã của bạn là phá hoại (Tôi sẽ cho bạn, như một bài tập, tìm cách người ta có thể truy cập vào các phần private của một lớp công chúng sử dụng một bẩn hành vi không xác định Hack ...), có chuyện gì private
là private
, ngay cả khi nó hiển thị trong private
phần của một lớp được khai báo trong một tiêu đề.
Tuy nhiên, nếu bạn cần thêm một "chức năng riêng tư" khác có quyền truy cập vào thành viên riêng tư, bạn vẫn phải khai báo nó với tất cả mọi người bằng cách sửa đổi tiêu đề, đó là một nghịch lý theo như tôi nghĩ: Nếu tôi thay đổi việc thực hiện mã của tôi (phần CPP), sau đó giao diện (phần HPP) KHÔNG nên thay đổi. Trích dẫn Leonidas: " Đây là ENCAPSULATION! "
Chỉnh sửa 2014-09-20
Khi nào các phương thức tĩnh thực sự tốt hơn các không gian tên với các hàm không phải là thành viên?
Khi bạn cần nhóm các chức năng lại với nhau và đưa nhóm đó vào một mẫu:
namespace alpha
{
void foo() ;
void bar() ;
}
struct Beta
{
static void foo() ;
static void bar() ;
};
template <typename T>
struct Gamma
{
void foobar()
{
T::foo() ;
T::bar() ;
}
};
Gamma<alpha> ga ; // compilation error
Gamma<Beta> gb ; // ok
gb.foobar() ; // ok !!!
Bởi vì, nếu một lớp có thể là một tham số mẫu, thì một không gian tên không thể.