2009-06-25 15 views
5

Tôi có một lớp học với hai chức năng thành viên chia sẻ một đoạn mã:Điều nào là tốt nhất cho một đoạn mã lặp lại?

void A::First() 
{ 
    firstFunctionEpilogue(); 
    sharedPart(); 
} 

void A::Second() 
{ 
    secondFunctionEpilogue(); 
    sharedPart(); 
} 

Hiện nay firstFunctionEpilogue(), secondFunctionEpilogue()sharedPart() đang không hoạt cuộc gọi nhưng chỉ là những mảnh mã, sharedPart() mã đang được nhân đôi. Tôi muốn thoát khỏi sự trùng lặp.

Đoạn mã được chia sẻ không cần quyền truy cập vào bất kỳ thành viên nào của lớp học. Vì vậy, tôi có thể thực hiện nó như bất kỳ của ba:

  • một hàm thành viên tĩnh,
  • một const không tĩnh hàm thành viên hoặc
  • một chức năng địa phương.

Biến thể nào tốt hơn và tại sao?

+0

Chỉ vì phần mã này xuất hiện hai lần, điều đó không có nghĩa là bạn phải tự tạo phương thức đó. Bạn muốn đạt được điều gì? –

+1

Bạn làm gì trong sharedPart() nếu nó không phụ thuộc vào cũng không làm thay đổi trạng thái của một đối tượng? – Tobias

+6

@ammoQ: Bạn có đề xuất sao chép mã ở cả hai nơi không. Đó là một ý tưởng khủng khiếp. –

Trả lời

5

Nếu chức năng của bạn truy cập trạng thái nhưng không thay đổi, hãy sử dụng hàm thành viên const.

trường hợp của bạn:

Nếu chức năng của bạn 1) không cần truy cập vào bất kỳ thành viên của mã này, và 2) có liên quan đến lớp, sau đó làm cho nó một chức năng tĩnh của lớp học của bạn.

Bằng cách đó, rõ ràng là nó không sửa đổi trạng thái, cũng không dựa trên trạng thái của đối tượng.

Một trường hợp có thêm bạn không đề cập đến:

Còn có một điều bạn có thể làm quá. Và đó là để làm cho SharedPart của bạn có trong một con trỏ hàm thành viên và gọi nó và sau đó xử lý nó là cơ thể chính. Nếu bạn có nhiều hàm First(), Second(), Third(), Fourth(), ... như vậy thì điều này có thể dẫn đến việc sao chép mã ít hơn. Bằng cách đó bạn không cần phải tiếp tục gọi SharedPart(); ở cuối mỗi hàm thành viên, và bạn có thể tái sử dụng First(), Second(), THird(), ... mà không cần gọi đến SharedPart() của mã.

+1

Tôi muốn làm cho nó trở thành một chức năng không phải là thành viên (có thể bị ẩn đi trong một không gian tên phụ để làm cho nó rõ ràng rằng nó không có nghĩa là được sử dụng bình thường), nhưng một thành viên tĩnh cũng sẽ làm việc. Điều chính là nếu nó không cần quyền truy cập vào các thành viên riêng của lớp, nó không nên * có * quyền truy cập. – jalf

+0

"nếu không cần quyền truy cập vào các thành viên riêng tư của lớp học, không nên * có * quyền truy cập". Cá nhân tôi sẽ quan tâm nhiều hơn về điều này nếu không phải vì hầu hết các chức năng của thành viên đều có quyền truy cập vào các thành viên riêng mà họ không cần truy cập - đặc biệt là vì sử dụng một thành viên mà họ cần truy cập vào toàn bộ. Thỉnh thoảng bạn chỉ có thể quay lại với chính mình để không bị vặn lên ;-) –

+0

Từ những gì tôi thấy, rất nhiều người đã đọc hiệu quả C++ tại đây :) –

1

Hoặc có thể ở một lớp khác.

Hoặc, nếu là thành viên, nó có thể là ảo.

Có rất nhiều quyết định và tôi sẽ không nhấn mạnh quá nhiều. Nói chung, tôi chọn không tham gia một hàm thành viên không tĩnh như là một mặc định trừ khi tôi có một lý do chính đáng để không làm theo cách đó.

  1. thích tĩnh nếu khách hàng cần phải gọi nó mà không cần phải một thể hiện
  2. thích chức năng địa phương nếu bạn không muốn lộn xộn file .h hoặc bạn muốn nó hoàn toàn ẩn trong .c
+0

+1 cho các chức năng cục bộ .. dunno lý do bạn bị downvoted – Tom

+0

Thái độ đối với các hàm cục bộ là một sự liên quan đến sự tinh khiết. Các hàm cục bộ phá vỡ rất nhiều (tốt, tất cả) các nguyên tắc thiết kế, nhưng đôi khi có thể thuận tiện về mặt thực tế.Kể từ khi câu hỏi này được gắn thẻ "thực hành tốt nhất" - 'goto' và 'chức năng địa phương' có lẽ là câu trả lời sai – ima

+0

Tôi đã đưa ra lý do để thích chúng - nếu bạn cần thứ gì đó bị ẩn khỏi .h, sử dụng chúng, nếu không, có thể không sử dụng chúng. –

3

tôi muốn nói:

  • nó có lẽ không quan trọng, vì vậy nó không quá nhiều "thực hành tốt nhất" là "chỉ không làm bất cứ điều gì điên".
  • Nếu lớp và tất cả các thành viên của lớp được xác định trong tiêu đề của nó, thì hàm thành viên tĩnh riêng có lẽ là tốt nhất, vì nó chỉ rõ "không dành cho khách hàng". Nhưng có nhiều cách để làm điều này cho một chức năng không phải thành viên: không ghi lại nó, đặt trong một bình luận "không cho khách hàng", và dính toàn bộ điều trong namespace beware_of_the_leopard.
  • Nếu các hàm thành viên của lớp được xác định trong tệp .cpp, thì các hàm trợ giúp nhỏ như thế này tốt nhất là các hàm miễn phí trong tệp .cpp. Hoặc là tĩnh hoặc trong một không gian tên ẩn danh.
+0

Đó là khá nhiều câu trả lời tôi sẽ đưa ra. Nếu nó không cần bất kỳ quyền truy cập vào các thành viên lớp và chỉ có các phương thức lớp gọi nó, làm cho nó trở thành một hàm trong một không gian tên ẩn danh trong tệp .cpp của lớp. –

0

một hàm thành viên tĩnh, một const không tĩnh hàm thành viên hoặc một địa phương chức năng.

Nói chung, nó phải là hàm thành viên của một lớp khác hoặc ít nhất là thành viên không tĩnh của lớp đó. Nếu chức năng này chỉ được gọi từ các thành viên thể hiện của một lớp - có lẽ ý nghĩa logic của nó đòi hỏi một cá thể, ngay cả khi cú pháp không. Có thể bất cứ điều gì ngoại trừ đối tượng này cung cấp các tham số có ý nghĩa hoặc sử dụng kết quả không?

Trừ khi có ý nghĩa khi gọi hàm này từ bên ngoài đối tượng đối tượng, nó không được tĩnh. Trừ khi nó có ý nghĩa để gọi chức năng này mà không truy cập vào lớp của bạn ở tất cả, nó không phải là địa phương.

Ví dụ vay từ nhận xét của Brian: nếu chức năng này thay đổi trạng thái toàn cầu, nó phải là thành viên của một nhóm trạng thái toàn cầu; nếu chức năng này ghi vào tệp, nó phải là thành viên của một lớp định dạng tệp; nếu đó là màn hình làm mới, nó phải là thành viên của ... vv Thậm chí nếu nó là một biểu thức số học đơn giản, nó có thể hữu ích để làm cho nó thành viên (tĩnh hay không) của một số lớp học ArithmeticsForSpecificPurpose.

1

Làm cho nó một tổ chức phi thành viên chức năng

Các mảnh chia sẻ mã không cần truy cập vào bất kỳ thành viên của lớp.

Như một quy tắc chung, nếu một đoạn mã không cần quyền truy cập vào bất kỳ thành viên nào của lớp không làm cho nó trở thành chức năng của thành viên! Cố gắng đóng gói các lớp của bạn càng nhiều càng tốt.

Tôi muốn đề xuất thực hiện chức năng không phải thành viên trong một không gian tên riêng biệt sẽ gọi các phương thức công khai và sau đó gọi hàm bạn đã tạo cho mã được chia sẻ.

Dưới đây là một ví dụ về những gì tôi có nghĩa là:

namepsace Astuff{ 
    class A{...}; 

    void sharedPart(){...}; 

    void first(const A& a); 
    void second(const A& a); 
} 

void Astuff::first(const A& a){ 
    a.first(); 
    sharedPart(); 
} 
0

Làm cho nó một tổ chức phi hàm thành viên không làm bạn. Scott Meyer có một lời giải thích tuyệt vời cho điều này here (và cũng Item 23 của hiệu quả C + + 3rd Edition).

0

Như một quy tắc chung "hãy cố gắng giữ nó ở chế độ cục bộ nhất có thể nhưng có thể nhìn thấy khi cần thiết".

Nếu tất cả mã gọi hàm nằm trong cùng một tệp triển khai, điều này có nghĩa là giữ mã cục bộ cho tệp triển khai.

Nếu bạn đặt phương thức tĩnh riêng tư cho lớp học của mình, nó sẽ không thể gọi được bởi các triển khai bao gồm cả lớp của bạn, nhưng nó vẫn hiển thị với chúng.Vì vậy, mỗi khi bạn thay đổi ngữ nghĩa của phương thức đó, tất cả các hiện thực bao gồm các cuộc gọi của bạn sẽ phải biên dịch lại - đó là một gánh nặng, kể từ quan điểm của họ, họ thậm chí không cần phải biết những điều đó.

Vì vậy, để giảm thiểu các phụ thuộc không cần thiết, bạn sẽ muốn làm cho nó trở thành một hàm toàn cầu tĩnh. Tuy nhiên, nếu bạn đã từng thấy mình lặp lại chức năng toàn cục này trong các tập tin thực thi mulitple, nó sẽ là thời gian để di chuyển hàm vào một cặp tập tin header/implementaion riêng biệt, để tất cả người gọi có thể bao gồm nó.

Cho dù bạn đặt chức năng đó vào không gian tên, ở phạm vi toàn cầu hay là một hàm tĩnh trong một lớp thực sự là rất thích hợp.

Trên lưu ý cuối cùng, nếu bạn sử dụng chức năng tĩnh toàn cục, có phiên bản "thêm C++ như": các không gian tên ẩn danh. Nó có thuộc tính tốt đẹp mà nó thực sự có thể lưu trữ trạng thái và cũng ngăn cản người dùng có thể thậm chí chuyển tiếp khai báo bất kỳ chức năng nào của nó.

// in your .cpp file 
namespace /*anonymous*/ 
{ 
    void foo() 
    { 
    // your code here 
    } 
}; 

void MyClass::FooUser1() { foo(); } 
void MyClass::FooUser2() { foo(); } 
Các vấn đề liên quan