Khi nào 'hàm tĩnh' được sử dụng?


24

OK, tôi đã học được chức năng tĩnh là gì, nhưng tôi vẫn không hiểu tại sao chúng hữu ích hơn chức năng thành viên tư nhân. Đây có thể là một loại câu hỏi mới ở đây, nhưng tại sao không chỉ thay thế tất cả các hàm thành viên riêng bằng các hàm tĩnh thay thế?


1
Không phải đó là "thay thế tất cả các chức năng tĩnh bằng chức năng thành viên tư nhân"? Hiện tại, bạn đang nói rằng bạn không thấy điểm của các phương thức tĩnh và tiếp tục hỏi tại sao chúng ta không sử dụng nhiều hơn chúng.

5
"Hàm tĩnh" là gì? Trong C ++, có ít nhất hai ý nghĩa (và cuối cùng tôi đã xem bản nháp C ++ 11, họ đã xóa thông báo phản đối staticvì đã giới hạn các chức năng trong phạm vi tệp.
David Thornley

Bạn có nghĩa là "hàm tĩnh" theo nghĩa của hàm tĩnh không có phạm vi tệp trong C / C ++, hay là "hàm / phương thức ghi nhớ tĩnh"? Đó là sự khác biệt rất lớn!
Jan Hudec

@JanHudec: Tôi nghĩ rằng với sự hiện diện của private memberchúng ta có thể giả định rằng OP đang hỏi về khái niệm OO và không có manh mối nào về phạm vi tĩnh của tệp.
Matthieu M.

@MatthieuM.: Thật ra sự hiện diện của 'thành viên tư nhân' chính xác là điều khiến tôi tin rằng anh ta có nghĩa là các hàm tĩnh theo nghĩa C ++. Bởi vì các hàm tĩnh trong phạm vi tệp và các hàm thành viên riêng là hai thứ có cách sử dụng rất giống nhau trong C ++, trong khi thay thế thành viên tĩnh công khai bằng thành viên không tĩnh riêng tư chỉ không có ý nghĩa nhiều. Thật không may, OP dường như không đáp ứng.
Jan Hudec

Câu trả lời:


24

Giả sử rằng bạn đang sử dụng OOP , hãy sử dụng các hàm tĩnh khi chúng không phụ thuộc vào bất kỳ thành viên nào trong lớp. Chúng vẫn có thể là riêng tư, nhưng theo cách này chúng được tối ưu hóa vì chúng không phụ thuộc vào bất kỳ trường hợp nào của đối tượng liên quan.

Khác với ở trên, tôi thấy các hàm tĩnh hữu ích khi bạn không muốn tạo một thể hiện của một đối tượng chỉ để thực thi một hàm công khai trên nó. Đây chủ yếu là trường hợp cho các lớp của trình trợ giúp có chứa các chức năng công cộng để thực hiện một số công việc lặp đi lặp lại và chung, nhưng không cần duy trì bất kỳ trạng thái nào giữa các cuộc gọi.


Cảm ơn bạn Bernard. Btw, bạn có biết ý nghĩa của trình biên dịch là "liên kết một phương thức với lớp" không?
Dark Templar

@Dark Templar: Không thể nói rằng tôi làm. Đây có phải là cụ thể cho một ngôn ngữ cụ thể?
Bernard

Tôi có một vấn đề nhỏ với định nghĩa của bạn "họ không phụ thuộc vào bất kỳ thành viên nào trong lớp". Các hàm tĩnh thành viên không thể truy cập bất kỳ thành viên không tĩnh nào, tuy nhiên chúng có thể truy cập các thành viên tĩnh. Thành viên tĩnh là thành viên của lớp.
in

@newprint: Bạn đúng, tuy nhiên đó không phải là điều tôi nói. Tôi đã nói khi họ không phụ thuộc vào bất kỳ thành viên nào trong lớp. Sử dụng các thành viên tĩnh là tốt nếu họ cần thiết, nhưng điều đó có thể không phải luôn luôn như vậy.
Bernard

8

Cố gắng giải thích đơn giản hơn những điều trên (những điều khá tốt).

Một đối tượng là mã + dữ liệu bình thường. Phương thức tĩnh được sử dụng khi bạn chỉ có phần "mã" để xử lý (không có dữ liệu / trạng thái nào được duy trì (ngoại trừ thành viên dữ liệu tĩnh)).


5

Bởi vì họ không yêu cầu một ví dụ và có thể công khai. Giả sử bạn cần một hàm để có mẫu số chung lớn nhất (GCD; rất hữu ích cho các lớp phân số; và vâng, đây chỉ là một ví dụ đơn giản). Không có điểm nào trong việc tạo ra một lớp các đối tượng với mục đích duy nhất là bạn có thể có một thiscon trỏ mà bạn không cần cũng không sử dụng gcd. Vì vậy, bạn sử dụng một phương thức tĩnh cho nó, lý tưởng là trên lớp thực sự sử dụng GCD (ví dụ trong lớp phân số).

Nếu bạn chỉ có các phương thức tĩnh, bạn đang thực hiện OOP sai và nên chuyển sang thực sự làm OOP hoặc sử dụng ngôn ngữ phù hợp hơn với mô hình của bạn.


Chẳng phải sẽ tốt hơn trong ví dụ của bạn khi sử dụng chức năng miễn phí sao?
Ela782

2
@ Ela782 Nếu ngôn ngữ có chức năng miễn phí, có.

Được rồi, cảm ơn vì sự yên tâm. Tôi chỉ học được cách thực hành tốt nhất này gần đây. Tuy nhiên, sau đó tôi gặp khó khăn khi thấy chức năng thành viên tĩnh công khai thực sự hữu ích, hãy nói bằng một ngôn ngữ như C ++. Ca sử dụng cho cả hai là khi hàm không phụ thuộc hoặc cần một thể hiện của lớp, và sau đó, các hàm miễn phí là khuyến nghị. Có lẽ đây là một câu hỏi mới.
Ela782

1
@ Ela782 Vâng, nó có thể là một câu hỏi hay. Hai điểm nhanh: Trong C ++ cụ thể, các thành viên tĩnh rất hữu ích cho lập trình meta mẫu vì bạn có thể truyền một kiểu làm tham số mẫu nhưng không phải là không gian tên. Nói chung, các hàm tĩnh có thể được sử dụng để chỉ ra rằng hàm thực sự thuộc về một số lớp, trái ngược với việc chỉ thuộc về một không gian tên (think stuff::Thing::Load(...)vs stuff::LoadThing()).

2

Tôi sử dụng chúng như các hàm trợ giúp cho các tác vụ thông thường, ví dụ:

  • Chuyển đổi độ thành radian (và ngược lại);
  • Băm một chuỗi;
  • Chuyển đổi từ enum sang thứ khác (trong dự án này tôi đang làm việc, chúng hoạt động như một bảng băm);

Hầu hết các tệp của tôi có chức năng tĩnh nhóm có hậu tố Helper, nghĩa là đó là những gì chúng làm, giúp tôi đến một nơi nào đó nhanh hơn.


2

Đối với phương thức tĩnh là gì:

Các phương thức tĩnh không yêu cầu một thể hiện của lớp cũng như chúng không thể truy cập ngầm định dữ liệu (hoặc cái này, tự, tôi, v.v.) của một thể hiện đó. [ 1 ]

Ví dụ về khi phương thức tĩnh hữu ích:

  • Phương pháp toàn cầu / trợ giúp
  • Nhận kết quả truy vấn từ lớp Mô hình Dữ liệu (gọi SP)

Chỉ cần sử dụng chúng khi thích hợp mà thôi.

  1. Nếu bạn thấy mình sao chép cùng một phương thức trong nhiều đối tượng, hãy xem xét làm cho phương thức tĩnh để bạn có thể theo dõi DRY.
  2. Sử dụng các phương thức tĩnh nếu bạn không cần một thể hiện của một đối tượng (bạn không làm việc trên và các biến đối tượng của đối tượng)

Nếu nhiều dữ liệu của bạn nằm ngoài các đối tượng và chúng đang được xử lý thông qua các phương thức tĩnh thì mã của bạn không hướng đối tượng và có thể trở nên khó bảo trì.


1

Trên thực tế, tĩnh và riêng tư là trực giao: một phương thức có thể là tĩnh hoặc riêng tư hoặc không hoặc cả hai.

Tĩnh so với không tĩnh (còn gọi là 'phương thức cá thể') cho biết phương thức đó hoạt động trên chính lớp đó (tĩnh) hay trên một cá thể cụ thể (không tĩnh). Tùy thuộc vào ngôn ngữ, bạn có thể gọi một phương thức tĩnh thông qua một thể hiện, nhưng bạn không bao giờ có thể truy cập thể hiện đó thông qua một phương thức tĩnh (điều này cũng ngụ ý rằng bạn không thể gọi bất kỳ phương thức không tĩnh nào từ bên trong một phương thức tĩnh, đơn giản vì bạn không có thisvật). Sử dụng các phương thức tĩnh để thực hiện hành vi được liên kết về mặt khái niệm với lớp, nhưng không 'liên kết' với một trường hợp cụ thể. Một kịch bản khác mà bạn có thể muốn sử dụng các phương thức tĩnh là khi bạn có một hàm hoạt động trên hai phiên bản của một lớp và không toán hạng nào xứng đáng có trạng thái đặc quyền - ví dụ: giả sử bạn có một lớpVectorvà bạn muốn thực hiện bổ sung; phương pháp bổ sung của bạn có thể được gọi là a.Add(b), nhưng Vector.Add(a, b)có lẽ có ý nghĩa hơn.

Riêng tư so với công chúng là về khả năng hiển thị của phương pháp. Các phương thức riêng tư chỉ có thể được truy cập từ trong phạm vi riêng của lớp, trong khi các phương thức công khai có thể truy cập được từ mọi nơi. Việc sử dụng quan trọng nhất cho việc này là đóng gói: bằng cách chỉ công khai các phương thức và thuộc tính đó là phần còn lại của mã cần thiết để giao tiếp với lớp của bạn, bạn hạn chế các điểm mà mã bên ngoài có thể đưa ra các vấn đề và bạn ngăn chặn các vấn đề bên trong lớp học của bạn từ chảy máu vào phần còn lại của dự án.

Vì vậy, quy tắc của ngón tay cái:

  • đặt tất cả các hàm thành viên thành riêng tư, ngoại trừ các hàm cần được gọi từ bên ngoài lớp
  • làm cho tất cả các phương thức cá thể phương thức, trừ khi chúng có ý nghĩa ngay cả khi không có cá thể của lớp tồn tại

0

Tôi sử dụng các phương thức tĩnh trong cả C ++ và C # cho các lớp Utility, các lớp không có bất kỳ dữ liệu cá thể nào, chỉ là một cách để gói một tập hợp các phương thức hữu ích, có liên quan.

int count1 = DBUtil::GetCountOfSlackerEmployees();
int count2 = DBUtil::GetCountOfEmployedSlackers();

0

Giả sử bạn đang nói về C ++ (bạn không nói) và bạn có các điều khoản đúng (nghĩa là không có nghĩa là các hàm / phương thức thành viên):

Ngay cả một hàm thành viên riêng vẫn phải được khai báo trong tiêu đề, điều đó có nghĩa là nó thực sự trở thành một phần của API và ABI của lớp, mặc dù người dùng thực sự không thể gọi nó. Nếu bạn thêm, sửa đổi hoặc xóa chức năng thành viên riêng tư, bạn đang buộc biên dịch lại tất cả các lớp phụ thuộc (tiêu đề đã thay đổi, không thể biết rõ hơn) và khi bạn làm như vậy trong thư viện, bạn phải xem xét khả năng tương thích cho ứng dụng bằng cách sử dụng nó

Mặt khác, các hàm tĩnh trong phạm vi tệp không nhận được biểu tượng công khai, vì vậy bạn có thể thêm, sửa đổi hoặc xóa chúng theo ý muốn và không có gì ngoài một đơn vị biên dịch sẽ bị ảnh hưởng.


0

Thông thường, bạn cần một tĩnh chính để hoạt động như một điểm vào cho chương trình của bạn. Đó có thể là loại quan trọng.


0

Hàm tĩnh (và có ý nghĩa khác nhau cho thuật ngữ đó trong các ngôn ngữ khác nhau), không yêu cầu bất kỳ trạng thái nào được giữ lại giữa các cuộc gọi. Nếu nó gắn chặt về mặt khái niệm với những gì một lớp làm, hãy biến nó thành một hàm lớp (như trong một lớp không phải là một đối tượng), hoặc nếu không, hãy biến nó thành một hàm toàn cục (hoặc cấp độ mô-đun, bất cứ thứ gì). Nó không thuộc về một đối tượng nếu nó không có nhu cầu về trạng thái của đối tượng.

Nếu bạn luôn chuyển trạng thái sang trạng thái đó, thì đây không thực sự là một hàm không trạng thái, bạn chỉ đang tạo một hàm trạng thái với cú pháp không trạng thái. Trong trường hợp đó, nó có thể thuộc về đối tượng gọi hoặc có thể là cấu trúc lại để điều chỉnh tốt hơn trạng thái và hành vi được chỉ định.


0

"tại sao không chỉ thay thế tất cả các chức năng thành viên tư nhân bằng các chức năng tĩnh thay thế?"

... bởi vì một thành viên tư nhân có thể truy cập dữ liệu cá thể trong khi chỉ cho phép nó xảy ra từ các cuộc gọi được thực hiện bên trong các chức năng thành viên khác. Hàm tĩnh có thể là riêng tư, nhưng nó sẽ không thể thay đổi hoặc tham chiếu đến một thể hiện của lớp trừ khi thể hiện được truyền vào dưới dạng tham số.


0

Thật buồn cười khi không ai có thể đưa ra một câu trả lời hay. Tôi cũng không chắc cái này là cái nào cả. Bạn có lẽ nên coi đó là một gợi ý rằng chúng nên được sử dụng ít nhất có thể. Họ sau tất cả các thủ tục chứ không phải OOP.

Dưới đây là một số ví dụ:

Trong Obj-C, nơi chúng được gọi là phương thức lớp, chúng thường được sử dụng làm trình bao bọc phân bổ nơi đối tượng được đưa vào nhóm đếm tham chiếu trước khi được trả về.

Một ví dụ khác từ Obj-C là đăng ký một lớp mới vào bộ sưu tập lớp. Giả sử bạn có một tập hợp các lớp mỗi xử lý một loại tệp. Khi bạn tạo một lớp mới cho một loại tệp mới, bạn có thể đăng ký nó vào bộ sưu tập (một biến toàn cục) bằng cách sử dụng một phương thức tĩnh trong lớp xác định loại tệp.

Trong C ++, một cách sử dụng khác mà tôi có thể nghĩ đến là nhẹ nhàng bắt lỗi. Hàm xây dựng của bạn không thể thất bại, ngoại trừ bằng cách ném một ngoại lệ. Bạn có thể đặt biến đối tượng lỗi, nhưng điều đó không phải lúc nào cũng phù hợp. Thay vào đó, bạn có thể thực hiện các phần có thể thất bại trong trình bao bọc tĩnh, sau đó phân bổ và trả về đối tượng mới hoặc NULL khi không thành công.


0

Giả sử bạn muốn tính toán xoang của một cái gì đó.

Không có tĩnh:

Math math = new Math()
double y = math.sin(x)

Với tĩnh:

double y = Math.sin(x)

Nó không có ý nghĩa để làm cho sinkhông tĩnh. Nó là không trạng thái và chỉ xử lý đầu vào.

Các hàm tĩnh không được gắn với một đối tượng cụ thể. Chúng là các hàm "chung" độc lập với trạng thái bên trong của đối tượng.


Các phương thức tĩnh không "đảm bảo không trạng thái". Mặc dù đúng là họ không thể sử dụng dữ liệu cá thể, nhưng họ cũng có quyền truy cập vào một số trạng thái (cụ thể là các thành viên tĩnh, cả hai lớp mà phương thức tĩnh thuộc về và trạng thái hiển thị toàn cầu khác như các biến tĩnh của các lớp khác).

@delnan: đúng ... bạn nói đúng. Hãy để tôi sửa điều này ngay bây giờ.
dagnelies

Không có tĩnh : x.sin(). Câu trả lời của bạn cho rằng tội lỗi phải là một chức năng của "Toán học", trong khi nó rõ ràng hoạt động gấp đôi.
AjahnCharles

0

Khá muộn ở đây nhưng tôi muốn thử tạo một định nghĩa chính xác: các hàm tĩnh là các hàm không hoặc không thể tham chiếu các thuộc tính / phương thức thể hiện của lớp chứa.

Trong một số ngôn ngữ, như C #, có thể có các trường tĩnh hoặc thuộc tính trong các lớp tĩnh, do đó không chính xác khi nói rằng chúng không được sử dụng cho trạng thái; một hàm tĩnh có thể sử dụng trạng thái tĩnh (toàn cầu).

Về cơ bản, nó tập trung vào: các hàm tĩnh, giống như mọi thứ tĩnh, rất hữu ích khi chúng luôn có sẵn mà không phụ thuộc vào các trường hợp không tĩnh.

Các hàm trợ giúp, giống như các hàm toán học, là một ví dụ điển hình, nhưng có các hàm khác.

Nếu lớp bạn tạo yêu cầu dữ liệu là bất biến, thì có thể tạo ra các hàm tĩnh có trong một thể hiện và truyền một thể hiện mới vì cá thể không thể (hoặc không nên) thay đổi. Ví dụ, các lớp chuỗi có thể có các hàm tĩnh nhận một chuỗi (hoặc 2 hoặc nhiều hơn) và trả lại một chuỗi mới.

Một lý do khác có thể là có một lớp giữ trạng thái toàn cầu hoặc dữ liệu nào đó. Có thể có các hàm tĩnh hoạt động với các thuộc tính tĩnh hoặc các trường trong lớp tĩnh đó.


0

Tôi muốn chỉ ra một cách sử dụng tĩnh f () khác.

http://www.parashift.com/c++-faq/named-ctor-idiom.html

Hiểu rõ điều này: các statichàm cho phép bạn tạo "Trình xây dựng được đặt tên", tức là bạn đặt tên cho hàm tĩnh của mình bằng tên phù hợp và tự viết tài liệu, và hàm tĩnh này gọi một trong các hàm tạo (vì các hàm tạo có tên giống nhau và bạn có thể có một rất nhiều trong số họ, thật khó để phân biệt giữa chúng).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.