Tại sao sử dụng tiền tố trên các biến thành viên trong các lớp C ++


150

Rất nhiều mã C ++ sử dụng các quy ước cú pháp để đánh dấu các biến thành viên. Ví dụ phổ biến bao gồm

  • m_ thành viên cho các thành viên công cộng (nơi tất cả các thành viên công cộng được sử dụng)
  • _ MemberName cho các thành viên tin hoặc tất cả thành viên

Những người khác cố gắng thực thi bằng cách sử dụng này-> thành viên bất cứ khi nào một biến thành viên được sử dụng.

Theo kinh nghiệm của tôi, hầu hết các cơ sở mã lớn hơn đều thất bại trong việc áp dụng các quy tắc như vậy một cách nhất quán.

Trong các ngôn ngữ khác, những quy ước này ít phổ biến hơn. Tôi chỉ thấy nó thỉnh thoảng trong mã Java hoặc C #. Tôi nghĩ rằng tôi chưa bao giờ thấy nó trong mã Ruby hoặc Python. Do đó, dường như có một xu hướng với các ngôn ngữ hiện đại hơn để không sử dụng đánh dấu đặc biệt cho các biến thành viên.

Liệu quy ước này có còn hữu dụng ngày nay trong C ++ hay nó chỉ là lỗi thời. Đặc biệt là nó được sử dụng rất không nhất quán trên các thư viện. Không phải các ngôn ngữ khác cho thấy người ta có thể làm mà không có tiền tố thành viên?


15
Tôi thích nó; trong các cơ sở mã phức tạp, điều quan trọng là phải biết lọ nào là cục bộ và loại nào không. Tôi thường sử dụng tiền tố trong việc ép buộc này -> mà tôi thấy có rất nhiều kiểu gõ thêm và tùy chọn (trong khi việc đặt tên sẽ buộc bạn phải làm điều đó)
Joe

5
Bạn chưa bao giờ thấy nó trong Ruby vì @ cho thuộc tính và thành ngữ của việc tạo các bộ truy cập theo sở thích để sử dụng các thuộc tính trực tiếp.
Steve Jessop

6
Theo PEP, 8 biến thành viên không công khai sẽ được thêm tiền tố vào dấu gạch dưới trong Python (ví dụ self._something = 1:).
Nathan Osman

2
Không nên sử dụng tô sáng cú pháp của trình soạn thảo để xác định những điều này?
quá

2
Bạn đã thấy tương đương với this->membermã Python. Trong Python nó thường như vậy self.membervà nó không chỉ là một quy ước, nó được yêu cầu bởi ngôn ngữ.
matec

Câu trả lời:


48

Bạn phải cẩn thận với việc sử dụng dấu gạch dưới hàng đầu. Một dấu gạch dưới hàng đầu trước một chữ in hoa trong một từ được bảo lưu. Ví dụ:

_Foo

_L

là tất cả các từ dành riêng trong khi

_foo

_l

không. Có những tình huống khác mà việc gạch dưới hàng đầu trước chữ cái viết thường không được phép. Trong trường hợp cụ thể của tôi, tôi thấy _L tình cờ được dành riêng bởi Visual C ++ 2005 và cuộc đụng độ đã tạo ra một số kết quả không mong muốn.

Tôi đang trên hàng rào về việc nó hữu ích như thế nào để đánh dấu các biến cục bộ.

Đây là một liên kết về những định danh nào được bảo lưu: các quy tắc về cách sử dụng dấu gạch dưới trong định danh C ++ là gì?


4
Trên thực tế, cả _foo và _l đều được bảo lưu ở phạm vi không gian tên.

13
Nhưng họ là ok như tên biến thành viên. Tôi không có tiền tố gạch dưới, bởi vì các quy tắc quá khó hiểu và tôi đã bị đốt cháy trong quá khứ.
Juan

11
Đây không phải là những từ dành riêng. Họ là những cái tên dành riêng. Nếu chúng là những từ dành riêng, bạn hoàn toàn không thể sử dụng chúng. Bởi vì chúng là tên dành riêng, bạn có thể sử dụng chúng, nhưng có nguy cơ của riêng bạn.
TonyK

235

Tôi hoàn toàn ủng hộ tiền tố được thực hiện tốt .

Tôi nghĩ (Hệ thống) ký hiệu Hungary chịu trách nhiệm cho hầu hết các "rap xấu" mà tiền tố nhận được.

Ký hiệu này phần lớn là vô nghĩa trong các ngôn ngữ được gõ mạnh, ví dụ như trong C ++ "lpsz" để cho bạn biết rằng chuỗi của bạn là một con trỏ dài đến một chuỗi kết thúc nul, khi: kiến ​​trúc được phân đoạn là lịch sử cổ đại, các chuỗi C ++ là bởi các con trỏ quy ước chung để chấm dứt. mảng char và thực sự không khó để biết rằng "customerName" là một chuỗi!

Tuy nhiên, tôi sử dụng tiền tố để chỉ định sử dụng một biến (về cơ bản là "Ứng dụng tiếng Hungary", mặc dù tôi thích tránh thuật ngữ tiếng Hungary do nó có liên kết xấu và không công bằng với System Hungary) và đây là cách tiết kiệm thời gian rất tiện dụng và phương pháp giảm lỗi .

Tôi sử dụng:

  • m cho các thành viên
  • c cho hằng số / chỉ đọc
  • p cho con trỏ (và pp cho con trỏ tới con trỏ)
  • v cho dễ bay hơi
  • s cho tĩnh
  • i cho các chỉ mục và các vòng lặp
  • e cho các sự kiện

Trường hợp tôi muốn làm cho loại rõ ràng, tôi sử dụng các hậu tố tiêu chuẩn (ví dụ: Danh sách, ComboBox, v.v.).

Điều này làm cho lập trình viên nhận thức được việc sử dụng biến bất cứ khi nào họ nhìn thấy / sử dụng nó. Có thể cho rằng trường hợp quan trọng nhất là "p" cho con trỏ (vì cách sử dụng thay đổi từ var sang var-> và bạn phải cẩn thận hơn nhiều với con trỏ - NULL, số học con trỏ, v.v.), nhưng tất cả những cái khác đều rất tiện dụng.

Ví dụ: bạn có thể sử dụng cùng một tên biến theo nhiều cách trong một hàm duy nhất: (ở đây là một ví dụ về C ++, nhưng nó áp dụng như nhau cho nhiều ngôn ngữ)

MyClass::MyClass(int numItems)
{
    mNumItems = numItems;
    for (int iItem = 0; iItem < mNumItems; iItem++)
    {
        Item *pItem = new Item();
        itemList[iItem] = pItem;
    }
}

Bạn có thể thấy ở đây:

  • Không có sự nhầm lẫn giữa thành viên và tham số
  • Không có sự nhầm lẫn giữa index / iterator và các mục
  • Sử dụng một tập hợp các biến liên quan rõ ràng (danh sách mục, con trỏ và chỉ mục) để tránh nhiều cạm bẫy của các tên chung (mơ hồ) như "đếm", "chỉ mục".
  • Tiền tố giảm nhập (ngắn hơn và hoạt động tốt hơn với tự động hoàn thành) so với các lựa chọn thay thế như "itemIndex" và "itemPtr"

Một điểm tuyệt vời khác của các trình lặp "iName" là tôi không bao giờ lập chỉ mục một mảng với chỉ mục sai và nếu tôi sao chép một vòng lặp bên trong một vòng lặp khác, tôi không phải cấu trúc lại một trong các biến chỉ số vòng lặp.

So sánh ví dụ đơn giản phi thực tế này:

for (int i = 0; i < 100; i++)
    for (int j = 0; j < 5; j++)
        list[i].score += other[j].score;

(khó đọc và thường dẫn đến việc sử dụng "i" trong đó "j" được dự định)

với:

for (int iCompany = 0; iCompany < numCompanies; iCompany++)
    for (int iUser = 0; iUser < numUsers; iUser++)
       companyList[iCompany].score += userList[iUser].score;

(dễ đọc hơn nhiều và loại bỏ tất cả sự nhầm lẫn về lập chỉ mục. Với tính năng tự động hoàn thành trong các IDE hiện đại, đây cũng là cách nhanh chóng và dễ dàng để nhập)

Lợi ích tiếp theo là các đoạn mã không yêu cầu bất kỳ bối cảnh nào được hiểu. Tôi có thể sao chép hai dòng mã vào email hoặc tài liệu và bất kỳ ai đọc đoạn mã đó đều có thể cho biết sự khác biệt giữa tất cả các thành viên, hằng, con trỏ, chỉ mục, v.v. Tôi không phải thêm "oh, và hãy cẩn thận vì 'Dữ liệu' là một con trỏ tới một con trỏ ", vì nó được gọi là 'ppData'.

Và với cùng một lý do, tôi không cần phải rời mắt khỏi dòng mã để hiểu nó. Tôi không phải tìm kiếm trong mã để tìm xem 'dữ liệu' là cục bộ, tham số, thành viên hay hằng số. Tôi không phải di chuyển bàn tay của mình sang chuột để tôi có thể di con trỏ qua 'dữ liệu' và sau đó chờ một chú giải công cụ (đôi khi không bao giờ xuất hiện) để bật lên. Vì vậy, các lập trình viên có thể đọc và hiểu mã nhanh hơn đáng kể , vì họ không lãng phí thời gian tìm kiếm lên xuống hoặc chờ đợi.

(Nếu bạn không nghĩ rằng mình lãng phí thời gian tìm kiếm lên xuống để tìm ra công cụ, hãy tìm một số mã bạn đã viết cách đây một năm và không nhìn vào đó. Mở tệp và nhảy xuống một nửa mà không đọc nó. bạn có thể đọc từ thời điểm này trước khi bạn không biết liệu có thành viên, tham số hay cục bộ nào không. Bây giờ hãy chuyển đến một vị trí ngẫu nhiên khác ... Đây là điều tất cả chúng ta làm cả ngày khi chúng ta bước qua mã của người khác hoặc cố gắng hiểu làm thế nào để gọi chức năng của họ)

Tiền tố 'm' cũng tránh ký hiệu "này->" xấu xí và dài dòng, và sự không nhất quán mà nó đảm bảo (ngay cả khi bạn cẩn thận, bạn thường kết thúc bằng một hỗn hợp 'này-> dữ liệu' và 'dữ liệu' trong cùng một lớp, vì không có gì bắt buộc một cách viết chính tả của tên).

Ký hiệu 'này' nhằm giải quyết sự mơ hồ - nhưng tại sao bất cứ ai cũng cố tình viết mã có thể mơ hồ? Sự mơ hồ sẽ dẫn đến một lỗi sớm hay muộn. Và trong một số ngôn ngữ, 'điều này' không thể được sử dụng cho các thành viên tĩnh, vì vậy bạn phải giới thiệu 'trường hợp đặc biệt' theo phong cách mã hóa của mình. Tôi thích có một quy tắc mã hóa đơn giản duy nhất áp dụng ở mọi nơi - rõ ràng, rõ ràng và nhất quán.

Lợi ích lớn cuối cùng là với Intellisense và tự động hoàn thành. Hãy thử sử dụng Intellisense trên Windows Form để tìm sự kiện - bạn phải cuộn qua hàng trăm phương thức lớp cơ sở bí ẩn mà bạn sẽ không bao giờ cần phải gọi để tìm sự kiện. Nhưng nếu mọi sự kiện đều có tiền tố "e", chúng sẽ tự động được liệt kê trong một nhóm dưới "e". Do đó, tiền tố hoạt động để nhóm các thành viên, consts, sự kiện, vv trong danh sách intellisense, làm cho nó nhanh hơn và dễ dàng hơn để tìm thấy tên bạn muốn. (Thông thường, một phương thức có thể có khoảng 20-50 giá trị (địa phương, params, thành viên, consts, sự kiện) có thể truy cập trong phạm vi của nó. Nhưng sau khi nhập tiền tố (tôi muốn sử dụng một chỉ mục ngay bây giờ, vì vậy tôi nhập 'i. .. '), tôi được trình bày chỉ với 2-5 tùy chọn tự động hoàn thành.' Nhập thêm '

Tôi là một lập trình viên lười biếng, và quy ước trên giúp tôi tiết kiệm rất nhiều công việc. Tôi có thể viết mã nhanh hơn và tôi ít mắc lỗi hơn vì tôi biết mọi biến nên được sử dụng như thế nào.


Lập luận chống lại

Vậy, khuyết điểm là gì? Đối số điển hình chống lại tiền tố là:

  • "Đề án tiền tố là xấu / xấu" . Tôi đồng ý rằng "m_lpsz" và ilk của nó được suy nghĩ kém và hoàn toàn vô dụng. Đó là lý do tại sao tôi khuyên bạn nên sử dụng một ký hiệu được thiết kế tốt được thiết kế để hỗ trợ các yêu cầu của bạn, thay vì sao chép một cái gì đó không phù hợp với ngữ cảnh của bạn. (Sử dụng các công cụ thích hợp cho công việc).

  • "Nếu tôi thay đổi cách sử dụng một cái gì đó tôi phải đổi tên nó" . Vâng, tất nhiên là bạn làm, đó là tất cả những gì về tái cấu trúc và tại sao các IDE có các công cụ tái cấu trúc để thực hiện công việc này một cách nhanh chóng và không đau đớn. Ngay cả khi không có tiền tố, việc thay đổi cách sử dụng một biến gần như chắc chắn có nghĩa là tên của nó phải được thay đổi.

  • "Tiền tố chỉ làm tôi bối rối" . Như mọi công cụ cho đến khi bạn học cách sử dụng nó. Khi bộ não của bạn đã quen với các kiểu đặt tên, nó sẽ tự động lọc thông tin và bạn sẽ không thực sự bận tâm rằng các tiền tố còn ở đó nữa. Nhưng bạn phải sử dụng một sơ đồ như thế này trong một hoặc hai tuần trước khi bạn thực sự trở nên "thông thạo". Và đó là khi nhiều người nhìn vào mã cũ và bắt đầu tự hỏi làm thế nào họ từng quản lý mà không có sơ đồ tiền tố tốt.

  • "Tôi chỉ có thể nhìn vào mã để xử lý công cụ này" . Có, nhưng bạn không cần lãng phí thời gian để tìm mã khác hoặc ghi nhớ từng chi tiết nhỏ của nó khi câu trả lời ngay tại chỗ mà mắt bạn đã tập trung vào.

  • (Một số) thông tin đó có thể được tìm thấy chỉ bằng cách đợi một tooltip bật lên trên biến của tôi . Đúng. Khi được hỗ trợ, đối với một số loại tiền tố, khi mã của bạn biên dịch sạch sẽ, sau khi chờ đợi, bạn có thể đọc qua một mô tả và tìm thông tin mà tiền tố sẽ được truyền tải ngay lập tức. Tôi cảm thấy rằng tiền tố là một cách tiếp cận đơn giản hơn, đáng tin cậy hơn và hiệu quả hơn.

  • "Nó gõ nhiều hơn" . Có thật không? Một nhân vật nữa? Hoặc là nó - với các công cụ tự động hoàn thành IDE, nó thường sẽ giảm việc nhập, bởi vì mỗi ký tự tiền tố thu hẹp đáng kể không gian tìm kiếm. Nhấn "e" và ba sự kiện trong lớp của bạn bật lên trong intellisense. Nhấn "c" và năm hằng số được liệt kê.

  • "Tôi có thể sử dụng this->thay vì m" . Vâng, vâng, bạn có thể. Nhưng đó chỉ là một tiền tố xấu xí và dài dòng hơn nhiều! Chỉ có nó mang một rủi ro lớn hơn nhiều (đặc biệt là trong các nhóm) bởi vì trình biên dịch nó là tùy chọn , và do đó việc sử dụng nó thường không nhất quán. mmặt khác là ngắn gọn, rõ ràng, rõ ràng và không phải là tùy chọn, do đó khó khăn hơn nhiều để sử dụng nó.


6
Tôi có nghĩa là đã đọc rằng vấn đề với Hungarien Notation chỉ là do Simonyi bị hiểu lầm. Anh ta đã viết một tiền tố nên được sử dụng để chỉ ra loại biến trong đó anh ta có nghĩa là "loại" như trong "loại điều" chứ không phải kiểu dữ liệu theo nghĩa đen. Sau đó, những người làm nền tảng tại Microsoft đã chọn nó và đưa ra lpsz ... và phần còn lại là lịch sử ...
VoidPulum

19
"S là dành cho tĩnh" nghe khá giống hình thức "xấu" của tiếng Hungary đối với tôi.
jalf

6
@Mehrdad: Tôi không nghĩ zlà rất hữu ích trong một ngôn ngữ như C ++, trong đó loại chi tiết triển khai cấp thấp đó nên được gói gọn trong một lớp, nhưng trong C (trong đó việc chấm dứt bằng 0 là một sự khác biệt quan trọng) tôi đồng ý với bạn. IMO bất kỳ lược đồ nào chúng tôi sử dụng phải được điều chỉnh theo yêu cầu để phù hợp nhất với nhu cầu của chúng tôi - Vì vậy, nếu chấm dứt bằng không ảnh hưởng đến việc sử dụng biến của bạn, không có gì sai khi khai báo "z" một tiền tố hữu ích.
Jason Williams

14
The most important case is "p" for pointer (because the usage changes from var. to var-> and you have to be much more careful with pointers.Tôi hết lòng không đồng ý. Nếu tôi sử dụng một con trỏ sai, đơn giản là nó sẽ không biên dịch ( void*có thể là một ngoại lệ đối với các con trỏ kép). Và toàn bộ ->trên .là đủ để cho tôi biết đó là một con trỏ. Ngoài ra, nếu bạn đang sử dụng tự động hoàn tất, trình soạn thảo của bạn có thể có các chú giải công cụ khai báo, loại bỏ sự cần thiết phải thêm tiền tố cho thông tin biến. Bất kể, câu trả lời tốt.
Thomas Eding

5
Được khuyến khích cho các giải thích rõ ràng, toàn diện và thú vị, tuy nhiên có rất ít ở đây cho thấy làm thế nào điều này tiết kiệm thời gian trong C ++ YET vẫn không được sử dụng nhiều trong các ngôn ngữ khác.

115

Tôi thường không sử dụng tiền tố cho các biến thành viên.

Tôi đã từng sử dụng mtiền tố, cho đến khi ai đó chỉ ra rằng "C ++ đã có tiền tố tiêu chuẩn để truy cập thành viên : this->.

Vì vậy, đó là những gì tôi sử dụng bây giờ. Đó là, khi có sự mơ hồ , tôi thêm this->tiền tố, nhưng thông thường, không có sự mơ hồ nào tồn tại và tôi chỉ có thể tham khảo trực tiếp tên biến.

Đối với tôi, đó là điều tốt nhất của cả hai thế giới. Tôi có một tiền tố tôi có thể sử dụng khi tôi cần và tôi có thể bỏ nó ra bất cứ khi nào có thể.

Tất nhiên, đối trọng rõ ràng của điều này là "có, nhưng sau đó bạn không thể thấy trong nháy mắt liệu một biến có phải là thành viên của lớp hay không".

Tôi nói "vậy thì sao? Nếu bạn cần biết điều đó, lớp của bạn có thể có quá nhiều trạng thái. Hoặc hàm quá lớn và phức tạp".

Trong thực tế, tôi đã thấy rằng điều này hoạt động rất tốt. Là một phần thưởng bổ sung, nó cho phép tôi quảng bá một biến cục bộ cho một thành viên trong lớp (hoặc ngược lại) một cách dễ dàng mà không phải đổi tên nó.

Và tốt nhất của tất cả, nó là phù hợp! Tôi không phải làm bất cứ điều gì đặc biệt hoặc nhớ bất kỳ quy ước nào để duy trì tính nhất quán.


Nhân tiện, bạn không nên sử dụng dấu gạch dưới hàng đầu cho các thành viên trong lớp. Bạn nhận được một cách khó chịu gần với tên được bảo lưu bởi việc thực hiện.

Tiêu chuẩn dự trữ tất cả các tên bắt đầu bằng dấu gạch dưới kép hoặc dấu gạch dưới theo sau là chữ in hoa. Nó cũng bảo lưu tất cả các tên bắt đầu bằng một dấu gạch dưới trong không gian tên toàn cầu .

Vì vậy, một thành viên lớp có dấu gạch dưới hàng đầu theo sau là chữ cái viết thường là hợp pháp, nhưng sớm hay muộn bạn cũng sẽ làm như vậy với một định danh bắt đầu bằng chữ in hoa hoặc nói cách khác là phá vỡ một trong các quy tắc trên.

Vì vậy, nó dễ dàng hơn để tránh hàng đầu nhấp nhô. Sử dụng một dấu gạch dưới, hoặc một m_hoặc chỉ mtiền tố nếu bạn muốn mã hóa phạm vi trong tên biến.


"Vì vậy, một thành viên lớp có dấu gạch dưới hàng đầu theo sau là chữ cái viết thường là hợp pháp, nhưng sớm hay muộn bạn sẽ làm điều tương tự với một định danh bắt đầu bằng chữ in hoa, hoặc nói cách khác là phá vỡ một trong các quy tắc trên." - các biến thành viên lớp không có trong không gian tên toàn cầu, do đó, một dấu gạch dưới hàng đầu là an toàn, bất kể nó được theo sau bởi một chữ cái viết thường hay viết hoa.
mbarnett

3
@mbarnett: Không, gạch dưới theo sau là chữ hoa thường được bảo lưu nói chung , không chỉ trong không gian tên toàn cầu.
jalf

9
ngạc nhiên rằng phiếu bầu của câu trả lời này ít hơn tiền tố.
Marson Mao

Tôi đồng ý với câu trả lời này, chỉ sử dụng this->nếu bạn cần xác định rằng đó là biến thành viên, hoặc không, điều đó cũng tốt.
David Morton

Hơn nữa, bạn không phải ghi lại quy ước của mình để cung cấp mã của mình cho người khác. Mọi người đều hiểu ý this->nghĩa của nó.
Caduchon

34

Tôi thích dấu gạch dưới postfix, như thế:

class Foo
{
   private:
      int bar_;

   public:
      int bar() { return bar_; }
};

Tôi cũng vậy. Tôi cũng cung cấp cho người truy cập / người đột biến cùng tên.
Cướp

4
Hấp dẫn. Trông hơi xấu xí lúc đầu, nhưng tôi có thể thấy nó có ích như thế nào.
ya23

6
Tôi muốn nói rằng nó ít xấu xí hơn nhiều so với: "mBar" hoặc "m_bar".
sydan

6
nhưng sau đó bạn có vector<int> v_;và viết v_.push_back(5)cũng khá xấu xí
avim

4
Đó là phong cách Google C ++.
Justme0

20

Gần đây tôi có xu hướng thích tiền tố m_ thay vì không có tiền tố nào cả, lý do không quan trọng lắm đến việc gắn cờ các biến thành viên, nhưng nó tránh sự mơ hồ, giả sử bạn có mã như:

void set_foo(int foo) { foo = foo; }

Đó là nguyên nhân không hoạt động, chỉ có một foocho phép. Vì vậy, lựa chọn của bạn là:

  • this->foo = foo;

    Tôi không thích nó, vì nó gây ra bóng tham số, bạn không còn có thể sử dụng g++ -Wshadowcác cảnh báo, nó cũng dài hơn để gõ sau đó m_. Bạn cũng vẫn gặp phải xung đột khi đặt tên giữa các biến và hàm khi bạn có a int foo;và a int foo();.

  • foo = foo_; hoặc là foo = arg_foo;

    Đã sử dụng điều đó trong một thời gian, nhưng nó làm cho danh sách đối số trở nên xấu xí, tài liệu không nên xử lý sự không rõ ràng về tên trong quá trình thực hiện. Đặt tên xung đột giữa các biến và chức năng cũng tồn tại ở đây.

  • m_foo = foo;

    Tài liệu API luôn sạch sẽ, bạn không nhận được sự mơ hồ giữa các hàm và biến thành viên và sau đó nhập ngắn hơn this->. Nhược điểm duy nhất là nó làm cho các cấu trúc POD trở nên xấu xí, nhưng vì các cấu trúc POD không phải chịu sự mơ hồ về tên ở nơi đầu tiên, nên người ta không cần phải sử dụng nó với chúng. Có một tiền tố duy nhất cũng làm cho một vài thao tác tìm kiếm & thay thế dễ dàng hơn.

  • foo_ = foo;

    Hầu hết các lợi thế của việc m_áp dụng, nhưng tôi từ chối nó vì lý do thẩm mỹ, một dấu gạch dưới hoặc dấu gạch dưới hàng đầu chỉ làm cho biến trông không đầy đủ và không cân bằng. m_chỉ nhìn tốt hơn Việc sử dụng m_cũng có thể mở rộng hơn, vì bạn có thể sử dụng g_cho toàn cầu và s_cho thống kê.

PS: Lý do tại sao bạn không thấy m_trong Python hoặc Ruby là vì cả hai ngôn ngữ đều thi hành tiền tố của riêng chúng, Ruby sử dụng @cho các biến thành viên và Python yêu cầu self..


1
để công bằng, bạn đã bỏ lỡ ít nhất 2 tùy chọn khác, ví dụ: (a) sử dụng tên đầy đủ như foochỉ dành cho thành viên và thay vào đó sử dụng tên đơn hoặc tên ngắn cho các tham số hoặc địa phương / ví dụ khác, chẳng hạn như int f; hoặc (b) tiền tố các tham số hoặc các địa phương khác với một cái gì đó. điểm tốt lạim_ và pod, mặc dù; Tôi đã độc lập đến một sở thích để tuân theo cả hai nguyên tắc đó, trong hầu hết các phần.
gạch dưới

12

Khi đọc qua hàm thành viên, việc biết ai "sở hữu" từng biến là hoàn toàn cần thiết để hiểu ý nghĩa của biến. Trong một chức năng như thế này:

void Foo::bar( int apples )
{
    int bananas = apples + grapes;
    melons = grapes * bananas;
    spuds += melons;
}

... Thật dễ dàng để xem táo và chuối đến từ đâu, nhưng còn nho, dưa và spud thì sao? Chúng ta có nên nhìn vào không gian tên toàn cầu? Trong lớp khai báo? Biến là thành viên của đối tượng này hay là thành viên của lớp đối tượng này? Không biết câu trả lời cho những câu hỏi này, bạn không thể hiểu được mã. Và trong một hàm dài hơn, ngay cả các khai báo của các biến cục bộ như táo và chuối cũng có thể bị mất trong shuffle.

Chuẩn bị một nhãn nhất quán cho toàn cầu, biến thành viên và biến thành viên tĩnh (có lẽ là g_, m_ và s_ tương ứng) ngay lập tức làm rõ tình huống.

void Foo::bar( int apples )
{
    int bananas = apples + g_grapes;
    m_melons = g_grapes * bananas;
    s_spuds += m_melons;
}

Những thứ này có thể làm quen với lúc đầu, nhưng sau đó, những gì trong lập trình không? Có một ngày, ngay cả {và} trông cũng kỳ lạ với bạn. Và một khi bạn đã quen với chúng, chúng sẽ giúp bạn hiểu mã nhanh hơn nhiều.

.

Một sự phản đối có thể xảy ra với đối số trên sẽ là mở rộng đối số thành các loại. Cũng có thể đúng khi biết loại biến "là hoàn toàn cần thiết để hiểu ý nghĩa của biến". Nếu đó là như vậy, tại sao không thêm tiền tố vào mỗi tên biến xác định loại của nó? Với logic đó, bạn kết thúc với ký hiệu Hungary. Nhưng nhiều người thấy ký hiệu Hungary lao động, xấu xí và không có ích.

void Foo::bar( int iApples )
{
    int iBananas = iApples + g_fGrapes;
    m_fMelons = g_fGrapes * iBananas;
    s_dSpuds += m_fMelons;
}

người Hungary nàocho chúng tôi biết một cái gì đó mới về mã. Bây giờ chúng ta hiểu rằng có một số phôi ẩn trong hàm Foo :: bar (). Vấn đề với mã bây giờ là giá trị của thông tin được thêm bởi tiền tố Hungary là nhỏ so với chi phí trực quan. Hệ thống loại C ++ bao gồm nhiều tính năng để giúp các loại hoạt động tốt với nhau hoặc đưa ra cảnh báo hoặc lỗi biên dịch. Trình biên dịch giúp chúng ta đối phó với các kiểu mà chúng ta không cần ký hiệu để làm như vậy. Chúng ta có thể suy luận đủ dễ dàng để các biến trong Foo :: bar () có thể là số và nếu đó là tất cả những gì chúng ta biết, điều đó đủ tốt để có được sự hiểu biết chung về hàm. Do đó, giá trị của việc biết loại chính xác của từng biến là tương đối thấp. Tuy nhiên, độ xấu của một biến như "s_dSpuds" (hoặc thậm chí chỉ là "dSpuds") là tuyệt vời. Vì thế,


Cảm ơn ý tưởng s_. Có vẻ rất hữu ích, và bằng cách nào đó chưa bao giờ xảy ra với tôi.
Chris Olsen

10

Tôi không thể nói mức độ phổ biến của nó, nhưng nói cá nhân, tôi luôn luôn (và luôn luôn) tiền tố các biến thành viên của tôi với 'm'. Ví dụ:

class Person {
   .... 
   private:
       std::string mName;
};

Đó là hình thức tiền tố duy nhất tôi sử dụng (tôi rất chống ký hiệu Hungary) nhưng nó đã giúp tôi thay đổi tốt trong những năm qua. Bên cạnh đó, tôi thường ghét việc sử dụng dấu gạch dưới trong tên (hoặc bất kỳ nơi nào khác cho vấn đề đó), nhưng không tạo ra ngoại lệ cho tên macro tiền xử lý, vì chúng thường là chữ hoa.


5
Vấn đề với việc sử dụng m, thay vì m_ (hoặc _) là với thời trang hiện tại cho trường hợp lạc đà, điều này gây khó khăn cho việc đọc một số tên biến.
Martin Beckett

1
@Neil tôi với bạn. @mgb: Tôi ghét những cái tên bắt đầu bằng '_' Nó chỉ là một lời mời cho những điều sai lầm trong tương lai.
Martin York

1
@Neil: Bạn sử dụng quy ước nào sau đó, nếu bạn không sử dụng dấu gạch dưới và không sử dụng camelcase?
jalf

2
Tôi hiểu rằng đó là camelCase, điều này khiến việc sử dụng chỉ m cho các biến như 'apData' gây nhầm lẫn - nó trở thành 'mapData' thay vì 'm_apData'. Tôi sử dụng _camelCase cho các biến thành viên được bảo vệ / riêng tư vì nó nổi bật
Martin Beckett

10
@MartinBeckett: Bạn nên viết hoa atrong kịch bản đó-- bạn không làm đúng cách khác. mApData( mtiền tố, sau đó tên biến là apData).
Bạch kim Azure

8

Lý do chính cho tiền tố thành viên là để phân biệt giữa hàm thành viên cục bộ và biến thành viên có cùng tên. Điều này rất hữu ích nếu bạn sử dụng getters với tên của điều.

Xem xét:

class person
{
public:
    person(const std::string& full_name)
        : full_name_(full_name)
    {}

    const std::string& full_name() const { return full_name_; }
private:
    std::string full_name_;
};

Biến thành viên không thể được gọi là full_name trong trường hợp này. Bạn cần đổi tên hàm thành viên thành get_full_name () hoặc trang trí biến thành viên bằng cách nào đó.


1
Đây là lý do tôi tiền tố. Tôi nghĩ foo.name()là dễ đọc hơn nhiều so với foo.get_name()ý kiến ​​của tôi.
Khủng bố ngày

6

Tôi không nghĩ một cú pháp có giá trị thực so với cú pháp khác. Tất cả sôi sục, như bạn đã đề cập, về tính đồng nhất trên các tệp nguồn.

Điểm duy nhất mà tôi thấy các quy tắc đó thú vị là khi tôi cần 2 thứ có tên giống hệt nhau, ví dụ:

void myFunc(int index){
  this->index = index;
}

void myFunc(int index){
  m_index = index;
}

Tôi sử dụng nó để phân biệt hai. Ngoài ra khi tôi kết thúc các cuộc gọi, như từ windows DLL, RecvPacket (...) từ dll có thể được gói trong RecvPacket (...) trong mã của tôi. Trong những trường hợp cụ thể này, sử dụng tiền tố như "_" có thể làm cho cả hai trông giống nhau, dễ xác định đó là cái nào, nhưng khác với trình biên dịch


6

Một số câu trả lời tập trung vào tái cấu trúc, thay vì đặt tên cho các quy ước, như là cách để cải thiện khả năng đọc. Tôi không cảm thấy rằng cái này có thể thay thế cái khác.

Tôi đã biết các lập trình viên không thoải mái khi sử dụng các khai báo cục bộ; họ thích đặt tất cả các khai báo ở đầu một khối (như trong C), vì vậy họ biết nơi tìm chúng. Tôi đã thấy rằng, khi phạm vi cho phép, việc khai báo các biến trong đó chúng được sử dụng lần đầu tiên sẽ giảm thời gian tôi liếc ngược để tìm các khai báo. (Điều này đúng với tôi ngay cả đối với các hàm nhỏ.) Điều đó giúp tôi dễ hiểu mã hơn mà tôi đang xem.

Tôi hy vọng nó đủ rõ ràng như thế nào điều này liên quan đến các quy ước đặt tên thành viên: Khi các thành viên có tiền tố thống nhất, tôi không bao giờ phải nhìn lại tất cả; Tôi biết khai báo thậm chí sẽ không được tìm thấy trong tập tin nguồn.

Tôi chắc chắn rằng tôi đã không bắt đầu thích những phong cách này. Tuy nhiên, theo thời gian, làm việc trong môi trường mà chúng được sử dụng một cách nhất quán, tôi đã tối ưu hóa suy nghĩ của mình để tận dụng lợi thế của chúng. Tôi nghĩ rằng có thể nhiều người hiện đang cảm thấy không thoải mái với họ cũng sẽ thích họ hơn, với việc sử dụng nhất quán.


5

Những quy ước đó chỉ có thế. Hầu hết các cửa hàng sử dụng quy ước mã để dễ đọc mã để mọi người có thể dễ dàng xem xét một đoạn mã và giải mã nhanh chóng giữa những thứ như thành viên công cộng và tư nhân.


"Giữa những thứ như thành viên công cộng và tư nhân" - điều này thực sự phổ biến đến mức nào? Tôi không nhớ là đã thấy nó, nhưng một lần nữa, tôi không đi xem xét lại các cơ sở mã hóa hay bất cứ điều gì.
gạch dưới

Tôi không làm điều đó bằng mã hóa của riêng mình, nhưng tôi đã làm việc ở những nơi mà chúng tôi phải làm điều đó dựa trên các hướng dẫn quy ước mã của họ. Tôi không thích làm điều đó vì hầu như tất cả các IDE sẽ hiển thị các biến riêng tư một màu khác nhau.
Ông Will

Hmm, tôi đoán nó chỉ xảy ra trong các tình huống khác với tôi. Thông thường tôi sử dụng một trong hai classes tất cả các thành viên có private/ protectedhoặc POD structcủa tất cả các biến có public(và thường là const). Vì vậy, tôi không bao giờ cần phải tự hỏi về mức độ truy cập của bất kỳ thành viên nào.
gạch dưới

5

Những người khác cố gắng thực thi bằng cách sử dụng này-> thành viên bất cứ khi nào một biến thành viên được sử dụng

Đó thường là vì không có tiền tố . Trình biên dịch cần đủ thông tin để giải quyết biến trong câu hỏi, có thể là một tên duy nhất vì tiền tố hoặc thông qua thistừ khóa.

Vì vậy, vâng, tôi nghĩ tiền tố vẫn hữu ích. Tôi, đối với một người, muốn nhập '_' để truy cập một thành viên hơn là 'this->'.


3
trình biên dịch có thể giải quyết nó bằng mọi cách ... các biến cục bộ sẽ ẩn các biến trong phạm vi cao hơn trong hầu hết các ngôn ngữ. Đó là vì lợi ích (đáng ngờ) của con người khi đọc mã. Bất kỳ IDE tốt nào cũng sẽ làm nổi bật người dân địa phương / thành viên / toàn cầu theo những cách khác nhau, do đó không cần loại công cụ này
rmeador

1
Chính xác. Người dân địa phương sẽ ẩn các thành viên trong lớp. Hãy xem xét một nhà xây dựng thiết lập các thành viên này. Thông thường nó có ý nghĩa để đặt tên cho các tham số giống như các thành viên.
Kent Boogaart

6
Tại sao đó là một mùi mã? Tôi muốn nói rằng nó hoàn toàn phổ biến và hợp lý, đặc biệt là khi nói đến các nhà xây dựng.
Kent Boogaart

3
Một constructor nên (nói chung) đặt các địa phương trong danh sách khởi tạo của nó. Và ở đó, các tham số không đổ bóng tên trường, nhưng cả hai đều có thể truy cập - vì vậy bạn có thể viếtstruct Foo { int x; Foo(int x) : x(x) { ... } };
Pavel Minaev

2
Tôi giả sử vấn đề xảy ra khi bạn Foo(int x, bool blee) : x(x) { if (blee) x += bleecount; } // oops, forgot this->muốn gọi các biến thành viên của mình một cái gì đó hữu ích và sau đó đưa ra các tham số hàm tạo khớp với các tên viết tắt:Foo(int f) : foo(f) {...}
Steve Jessop

4

Các ngôn ngữ khác sẽ sử dụng các quy ước mã hóa, chúng chỉ có xu hướng khác nhau. Ví dụ, C # có thể có hai kiểu khác nhau mà mọi người có xu hướng sử dụng, một trong những phương thức C ++ (_variable, mVariable hoặc các tiền tố khác như ký hiệu Hungary) hoặc phương thức mà tôi gọi là phương thức StyleCop.

private int privateMember;
public int PublicMember;

public int Function(int parameter)
{
  // StyleCop enforces using this. for class members.
  this.privateMember = parameter;
}

Cuối cùng, nó trở thành những gì mọi người biết, và những gì có vẻ tốt nhất. Cá nhân tôi nghĩ rằng mã dễ đọc hơn nếu không có ký hiệu Hungary, nhưng nó có thể trở nên dễ dàng hơn để tìm một biến có intellisense chẳng hạn nếu ký hiệu Hungary được đính kèm.

Trong ví dụ của tôi ở trên, bạn không cần tiền tố m cho các biến thành viên vì tiền tố sử dụng của bạn với điều này. chỉ ra điều tương tự trong một phương thức thực thi trình biên dịch.

Điều này không nhất thiết có nghĩa là các phương pháp khác là xấu, mọi người gắn bó với những gì hoạt động.


3

Khi bạn có một phương thức hoặc khối mã lớn, sẽ thuận tiện để biết ngay nếu bạn sử dụng biến cục bộ hoặc thành viên. đó là để tránh lỗi và cho sự rõ ràng tốt hơn!


3
Nếu bạn có một phương pháp lớn, để rõ ràng hơn, hãy phá vỡ nó.
sbi

4
Có rất nhiều lý do để không phá vỡ một số phương pháp lớn. Ví dụ: nếu phương thức của bạn cần giữ nhiều trạng thái cục bộ, bạn phải truyền nhiều tham số vào các phương thức phụ, tạo các lớp mới tồn tại chỉ với mục đích truyền dữ liệu giữa các phương thức này hoặc khai báo dữ liệu trạng thái như dữ liệu thành viên của lớp cha. Tất cả những điều này có vấn đề sẽ ảnh hưởng đến sự rõ ràng hoặc khả năng duy trì của phương pháp, so với một phương pháp dài duy nhất (đặc biệt là một phương pháp có logic đơn giản).
Steve Broberg

3
@sbi: Nguyên tắc chỉ có vậy; hướng dẫn, không phải quy tắc. Đôi khi bạn cần các phương thức lớn không cho phép mình bị chia tách một cách hợp lý và đôi khi các tên tham số đụng độ với các thành viên.
Ed S.

Xin đừng công khai các biến thành viên của bạn. Chỉ cần sử dụng phụ kiện. Các dấu ngoặc đơn nên cho người đọc biết đó là biến thành viên.
lừa

Lưu ý rằng có một cảnh báo trong gcc (> = 4.6) để phát hiện xung đột tên:-Wshadow
Caduchon

3

IMO, đây là cá nhân. Tôi không đặt bất kỳ tiền tố nào cả. Dù sao, nếu mã có nghĩa là công khai, tôi nghĩ nó nên có một số tiền tố, vì vậy nó có thể dễ đọc hơn.

Thông thường các công ty lớn đang sử dụng cái gọi là 'quy tắc nhà phát triển'.
Btw, trò vui nhất nhưng thông minh nhất mà tôi thấy là DRY KISS (Đừng lặp lại chính mình. Hãy giữ nó đơn giản, ngu ngốc). :-)


3

Như những người khác đã nói, tầm quan trọng là phải thông tục (các kiểu và quy ước đặt tên thích ứng với cơ sở mã mà bạn đang viết) và phải nhất quán.

Trong nhiều năm qua tôi đã làm việc trên một cơ sở mã lớn mà sử dụng cả hai công ước "this->" cũng như sử dụng một postfix ký hiệu gạch dưới cho các biến thành viên. Trong những năm qua, tôi cũng đã làm việc cho các dự án nhỏ hơn, một số trong đó không có bất kỳ quy ước nào để đặt tên biến thành viên và các quy ước khác có cách đặt tên biến thành viên. Trong số những dự án nhỏ hơn đó, tôi luôn thấy những dự án thiếu bất kỳ quy ước nào là khó khăn nhất để nhanh chóng nhảy vào và hiểu.

Tôi rất chú ý đến việc đặt tên. Tôi sẽ thống nhất tên được gán cho một lớp hoặc biến đến mức, nếu tôi không thể đưa ra một cái gì đó mà tôi cảm thấy là "tốt", tôi sẽ chọn đặt tên cho một cái gì đó vô nghĩa và đưa ra một nhận xét mô tả những gì nó thực sự Là. Theo cách đó, ít nhất cái tên có nghĩa chính xác những gì tôi dự định có nghĩa là - không hơn không kém. Và thông thường, sau khi sử dụng một thời gian, tôi phát hiện ra cái tên đó thực sự là gì và có thể quay lại và sửa đổi hoặc cấu trúc lại một cách thích hợp.

Một điểm cuối cùng về chủ đề IDE thực hiện công việc - đó là tất cả tốt và tốt, nhưng IDE thường không có sẵn trong môi trường nơi tôi đã thực hiện công việc khẩn cấp nhất. Đôi khi thứ duy nhất có sẵn tại thời điểm đó là một bản sao của 'vi'. Ngoài ra, tôi đã thấy nhiều trường hợp trong đó việc hoàn thành mã IDE đã lan truyền sự ngu ngốc như cách viết sai chính tả trong tên. Vì vậy, tôi không muốn phải dựa vào một cái nạng IDE.


3

Ý tưởng ban đầu cho tiền tố trên các biến thành viên C ++ là lưu trữ thông tin loại bổ sung mà trình biên dịch không biết. Vì vậy, ví dụ, bạn có thể có một chuỗi ký tự có độ dài cố định và một chuỗi khác là biến và được kết thúc bằng '\ 0'. Đối với trình biên dịch, chúng là cả hai char *, nhưng nếu bạn cố gắng sao chép từ cái này sang cái khác thì bạn sẽ gặp rắc rối lớn. Vì vậy, ra khỏi đỉnh đầu của tôi,

char *aszFred = "Hi I'm a null-terminated string";
char *arrWilma = {'O', 'o', 'p', 's'};

trong đó "asz" có nghĩa là biến này là "chuỗi ascii (không kết thúc) và" mảng "có nghĩa là biến này là một mảng ký tự.

Rồi phép màu xảy ra. Trình biên dịch sẽ hoàn toàn hài lòng với tuyên bố này:

strcpy(arrWilma, aszFred);

Nhưng bạn, với tư cách là một con người, có thể nhìn vào nó và nói "này, những biến đó không thực sự giống nhau, tôi không thể làm điều đó".

Thật không may, rất nhiều nơi sử dụng các tiêu chuẩn như "m_" cho các biến thành viên, "i" cho các số nguyên cho dù được sử dụng như thế nào, "cp" cho các con trỏ char. Nói cách khác, họ đang sao chép những gì trình biên dịch biết và làm cho mã khó đọc cùng một lúc. Tôi tin rằng hành vi độc hại này nên bị đặt ra ngoài vòng pháp luật và phải chịu hình phạt khắc nghiệt.

Cuối cùng, có hai điểm tôi nên đề cập:

  • Việc sử dụng thận trọng các tính năng của C ++ cho phép trình biên dịch biết thông tin bạn phải mã hóa theo các biến kiểu C thô. Bạn có thể tạo các lớp sẽ chỉ cho phép các hoạt động hợp lệ. Điều này nên được thực hiện nhiều như thực tế.
  • Nếu khối mã của bạn rất lâu đến nỗi bạn quên những gì gõ một biến là trước khi bạn sử dụng nó, họ có cách quá dài. Đừng sử dụng tên, tổ chức lại.

Các tiền tố chỉ ra loại hoặc loại biến cũng là một thứ đáng để thảo luận, nhưng tôi chủ yếu đề cập đến các tiền tố cho biết liệu thứ gì đó là thành viên / trường (riêng tư). Ký hiệu Hungary ngược mà bạn đang đề cập có thể khá tiện dụng khi được áp dụng một cách thông minh (như trong ví dụ của bạn). Ví dụ yêu thích của tôi, nơi nó có ý nghĩa là tọa độ tương đối và tuyệt đối. khi bạn thấy absX = relX, bạn có thể thấy rõ rằng có điều gì đó không ổn. Bạn cũng có thể đặt tên cho các hàm tương ứng: absX = absFromRel (relX, offset);
VoidPulum

Lưu ý: việc khởi tạo aszFred là đáng nghi ngờ (cung cấp quyền truy cập không phải là chuỗi ký tự) và việc khởi tạo của ArrayWilma thậm chí sẽ không được biên dịch. (Bạn có thể dự định khai báo ArrayWilma là một mảng, thay vì một con trỏ!) Không có vấn đề gì, như bạn đã viết rằng nó chỉ ở trên đỉnh đầu của bạn ... :-)
Niels Dekker

Rất tiếc, bạn hoàn toàn đúng. Trẻ em, đừng thử điều đó ở nhà. Thực hiện việc này: 'const char * aszFred = "Xin chào, tôi là một chuỗi kết thúc null"; char ArrayWilma [] = {'O', 'o', 'p', 's'}; '
AL Flanagan

3

Dự án của chúng tôi luôn sử dụng "của nó" làm tiền tố cho dữ liệu thành viên và "the" làm tiền tố cho các tham số, không có tiền tố cho người địa phương. Nó hơi khó hiểu, nhưng nó đã được các nhà phát triển đầu tiên của hệ thống của chúng tôi chấp nhận vì họ thấy nó được sử dụng như một quy ước của một số thư viện nguồn thương mại mà chúng tôi đang sử dụng vào thời điểm đó (cả XVT hoặc RogueWave - có thể cả hai). Vì vậy, bạn sẽ nhận được một cái gì đó như thế này:

void
MyClass::SetName(const RWCString &theName)
{
   itsName = theName;
}

Lý do lớn mà tôi thấy về các tiền tố phạm vi (và không có tiền tố nào khác - tôi ghét ký hiệu Hungary) là vì nó ngăn bạn khỏi rắc rối bằng cách viết mã khi bạn nghĩ rằng bạn đang đề cập đến một biến, nhưng bạn thực sự đang đề cập đến một biến khác với cùng tên được xác định trong phạm vi địa phương. Nó cũng tránh được vấn đề về việc đưa ra một tên biến để thể hiện cùng một khái niệm, nhưng với các phạm vi khác nhau, như ví dụ trên. Trong trường hợp đó, bạn sẽ phải đưa ra một số tiền tố hoặc tên khác cho tham số "theName" - tại sao không thực hiện quy tắc nhất quán áp dụng ở mọi nơi.

Chỉ sử dụng điều này-> không thực sự đủ tốt - chúng tôi không quan tâm đến việc giảm sự mơ hồ như chúng tôi đang trong việc giảm lỗi mã hóa và việc che giấu tên bằng các định danh phạm vi cục bộ có thể là một nỗi đau. Cấp, một số trình biên dịch có thể có tùy chọn đưa ra cảnh báo cho các trường hợp bạn đã che giấu tên ở phạm vi lớn hơn, nhưng những cảnh báo đó có thể gây phiền toái nếu bạn làm việc với một bộ thư viện bên thứ ba lớn đã chọn tên cho các biến không được sử dụng đôi khi va chạm với chính bạn.

Đối với chính nó - tôi thực sự thấy nó dễ gõ hơn so với dấu gạch dưới (như một người đánh máy cảm ứng, tôi tránh nhấn mạnh bất cứ khi nào có thể - kéo dài quá nhiều hàng nhà), và tôi thấy nó dễ đọc hơn một dấu gạch dưới bí ẩn.


Đây là giải pháp trực quan nhất với đường cong học tập nhanh nhất tôi từng nghe. Tôi ước các ngôn ngữ nói linh hoạt hơn để xử lý tất cả những ngôn ngữ đó để chúng tôi không phải suy nghĩ về việc đưa ra các kỹ thuật mới để giải quyết sự mơ hồ trong mã.
Guney Ozsan

2

Tôi sử dụng nó vì Intellisense của VC ++ không thể biết khi nào sẽ hiển thị các thành viên riêng tư khi truy cập ra khỏi lớp. Dấu hiệu duy nhất là một biểu tượng "khóa" nhỏ trên biểu tượng trường trong danh sách Intellisense. Nó chỉ làm cho việc xác định các thành viên tư nhân (các lĩnh vực) dễ dàng hơn. Cũng là một thói quen từ C # phải trung thực.

class Person {
   std::string m_Name;
public:
   std::string Name() { return m_Name; }
   void SetName(std::string name) { m_Name = name; }
};

int main() {
  Person *p = new Person();
  p->Name(); // valid
  p->m_Name; // invalid, compiler throws error. but intellisense doesn't know this..
  return 1;
}

2

Tôi nghĩ rằng, nếu bạn cần tiền tố để phân biệt các thành viên lớp với các tham số hàm thành viên và các biến cục bộ, thì hàm này quá lớn hoặc các biến bị đặt tên xấu. Nếu nó không vừa trên màn hình để bạn có thể dễ dàng nhìn thấy cái gì, hãy cấu trúc lại.

Cho rằng chúng thường được tuyên bố cách xa nơi chúng được sử dụng, tôi thấy rằng các quy ước đặt tên cho các hằng số toàn cầu (và các biến toàn cục, mặc dù IMO hiếm khi cần sử dụng chúng). Nhưng nếu không, tôi không thấy cần nhiều.

Điều đó nói rằng, tôi đã từng đặt dấu gạch dưới ở cuối của tất cả các thành viên lớp tư nhân. Vì tất cả dữ liệu của tôi là riêng tư, điều này ngụ ý các thành viên có dấu gạch dưới. Tôi thường không làm điều này nữa trong các cơ sở mã mới, nhưng vì là một lập trình viên, bạn chủ yếu làm việc với mã cũ, tôi vẫn làm điều này rất nhiều. Tôi không chắc liệu sự khoan dung của tôi đối với thói quen này xuất phát từ thực tế là tôi đã từng làm điều này luôn và vẫn đang thực hiện nó thường xuyên hay liệu nó có thực sự có ý nghĩa hơn việc đánh dấu các biến thành viên hay không.


2
Điều này phản ánh rất nhiều về cảm nhận của tôi về vấn đề này. Mã phải được đọc mà không cần dùng đến tiền tố. Có lẽ chúng ta không thấy quá nhiều tiền tố sử dụng trong các ngôn ngữ hiện đại hơn vì cộng đồng người dùng của họ đã chấp nhận khả năng đọc nhiều hơn một chút so với những gì bạn đôi khi thấy trong C ++. Tất nhiên, C ++ có thể và nên đọc được. Chỉ là rất nhiều C ++ không thể đọc được đã được viết trong những năm qua.
VoidPulum


1

Nó rất hữu ích để phân biệt giữa các biến thành viên và biến cục bộ do quản lý bộ nhớ. Nói rộng hơn, các biến thành viên được phân bổ heap nên được hủy trong hàm hủy, trong khi các biến cục bộ được phân bổ heap nên được hủy trong phạm vi đó. Áp dụng quy ước đặt tên cho các biến thành viên tạo điều kiện quản lý bộ nhớ chính xác.


làm sao vậy Hàm hủy không có quyền truy cập vào các biến cục bộ được khai báo trong các hàm khác, vì vậy không có chỗ cho sự nhầm lẫn ở đó. Bên cạnh đó, các biến cục bộ được phân bổ heap không nên tồn tại . Và các biến thành viên được phân bổ heap chỉ nên tồn tại trong các lớp RAII, khá nhiều.
jalf

"Các biến cục bộ được phân bổ heap không nên tồn tại" là một chút mạnh mẽ. Nhưng nếu / khi bạn sử dụng chúng, điều cực kỳ quan trọng là đảm bảo rằng chúng được xử lý một cách nghiêm túc, do đó, một quy ước đặt tên có kỷ luật đối với các thành viên so với các biến cục bộ sẽ hỗ trợ rất nhiều cho việc đảm bảo điều này.
frankster

1

Code Complete khuyến nghị m_varname cho các biến thành viên.

Mặc dù tôi chưa bao giờ nghĩ rằng ký hiệu m_ hữu ích, tôi sẽ đưa ra ý kiến ​​của McConnell trong việc xây dựng một tiêu chuẩn.


2
Không trừ khi anh ta giải thích tại sao gạch dưới. Tôi là một fan hâm mộ lớn của cuốn sách "Phát triển nhanh" của anh ấy, mà tôi đã đề xuất ở đây nhiều lần, nhưng ít hơn nhiều về "Hoàn thành mã" (mà tôi sẽ thừa nhận tôi đã không đọc kể từ khi nó ra mắt).

1

Tôi gần như không bao giờ sử dụng tiền tố trước tên biến của mình. Nếu bạn đang sử dụng một IDE đủ tốt, bạn sẽ có thể cấu trúc lại và tìm các tài liệu tham khảo một cách dễ dàng. Tôi sử dụng tên rất rõ ràng và không sợ có tên biến dài. Tôi chưa bao giờ gặp rắc rối với phạm vi với triết lý này.

Lần duy nhất tôi sử dụng tiền tố là trên dòng chữ ký. Tôi sẽ thêm tiền tố vào một phương thức với _ để tôi có thể lập trình phòng thủ xung quanh chúng.


1

Bạn không bao giờ cần một tiền tố như vậy. Nếu một tiền tố như vậy cung cấp cho bạn bất kỳ lợi thế nào, thì kiểu mã hóa của bạn nói chung cần sửa chữa và đó không phải là tiền tố giữ cho mã của bạn không rõ ràng. Tên biến xấu điển hình bao gồm "khác" hoặc "2". Bạn không khắc phục điều đó bằng cách yêu cầu nó phải khác, bạn sửa nó bằng cách khiến nhà phát triển suy nghĩ về biến đó đang làm gì trong bối cảnh của hàm đó. Có lẽ ông có nghĩa là remoteSide, hoặc newValue, hoặc secondTestListener hoặc một cái gì đó trong phạm vi đó.

Đó là một lỗi thời hiệu quả vẫn còn được truyền bá quá xa. Dừng tiền tố các biến của bạn và đặt cho chúng tên thích hợp có độ rõ ràng phản ánh thời gian chúng được sử dụng. Lên đến 5 dòng bạn có thể gọi nó là "i" mà không nhầm lẫn; ngoài 50 dòng bạn cần một cái tên khá dài.


1

Tôi thích các tên biến chỉ cung cấp một ý nghĩa cho các giá trị mà chúng chứa và để lại cách chúng được khai báo / triển khai ngoài tên. Tôi muốn biết giá trị nghĩa là gì, thời gian. Có thể tôi đã thực hiện nhiều hơn một lượng tái cấu trúc trung bình, nhưng tôi thấy rằng việc nhúng cách thực hiện một cái gì đó trong tên làm cho việc tái cấu trúc trở nên tẻ nhạt hơn mức cần thiết. Tiền tố chỉ ra vị trí hoặc cách các thành viên đối tượng được khai báo là cụ thể thực hiện.

color = Red;

Hầu hết thời gian, tôi không quan tâm nếu Red là enum, struct hay bất cứ thứ gì, và nếu chức năng này lớn đến mức tôi không thể nhớ nếu màu được khai báo cục bộ hay là thành viên, có lẽ đã đến lúc phải phá vỡ hàm thành các đơn vị logic nhỏ hơn.

Nếu độ phức tạp chu kỳ của bạn lớn đến mức bạn không thể theo dõi những gì đang diễn ra trong mã mà không có manh mối cụ thể về triển khai được nhúng trong tên của sự vật, rất có thể bạn cần giảm độ phức tạp của chức năng / phương thức.

Hầu hết, tôi chỉ sử dụng 'cái này' trong các hàm tạo và khởi tạo.


0

Tôi sử dụng m_ cho các biến thành viên chỉ để tận dụng Intellisense và chức năng IDE có liên quan. Khi tôi mã hóa việc triển khai một lớp, tôi có thể nhập m_ và xem hộp tổ hợp với tất cả các thành viên m_ được nhóm lại với nhau.

Nhưng dĩ nhiên tôi có thể sống mà không có vấn đề gì. Đó chỉ là phong cách làm việc của tôi.


Bạn cũng có thể gõthis->
Toast

0

Theo TIÊU CHUẨN LIÊN QUAN ĐẾN XE ĐIỆN C ++, C ++ CODING STANDARDS (tháng 12 năm 2005):

Quy tắc AV 67

Dữ liệu công khai và được bảo vệ chỉ nên được sử dụng trong các lớp không phải là lớp. Đặt vấn đề: Một lớp có thể duy trì sự bất biến của nó bằng cách kiểm soát truy cập vào dữ liệu của nó. Tuy nhiên, một lớp không thể kiểm soát quyền truy cập vào các thành viên của nó nếu các thành viên đó không riêng tư. Do đó tất cả dữ liệu trong một lớp nên ở chế độ riêng tư.

Do đó, tiền tố "m" trở nên không đáng tin vì tất cả dữ liệu phải ở chế độ riêng tư.

Nhưng đó là một thói quen tốt để sử dụng tiền tố p trước một con trỏ vì nó là một biến nguy hiểm.


0

Nhiều trong số những quy ước đó là từ thời không có biên tập viên tinh vi. Tôi khuyên bạn nên sử dụng một IDE thích hợp cho phép bạn tô màu mọi loại biến. Màu sắc dễ dàng nhận ra hơn bất kỳ tiền tố nào.

Nếu bạn cần nhận được nhiều chi tiết hơn về một biến, bất kỳ IDE hiện đại nào cũng có thể hiển thị nó cho bạn bằng cách di chuyển dấu mũ hoặc con trỏ qua nó. Và nếu bạn sử dụng một biến theo cách sai (ví dụ: một con trỏ với toán tử.), Bạn sẽ vẫn gặp lỗi.

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.