Tài liệu này liệt kê ra các quy chuẩn lập trình C++
thông dụng. Các quy chuẩn này được đưa ra dựa trên nhiều nguồn
tin, khảo sát, kinh nghiệm cá nhân của những lập trình viên C++.
Có nhiều lý do mà các quy chuẩn này được đưa ra,
trong đó lý do chính là đa phần các lập trình viên quá cá nhân và
gói gọn trong quy tắc của riêng họ, gây khó hiểu cho người tiếp nhận
mã nguồn, do đó những quy tắc cụ thể (đặc biệt là về đặt tên) cần
phải được xây dựng chung.
Những quy tắc này có kèm theo một số ví
dụ để người đọc để hiểu và dễ vận dụng. Trong các dự án thực
thường xảy ra vấn đề pha trộn giữa ngôn ngữ bình thường và ngôn ngữ
kỹ thuật gây khó hiểu, tài liệu này sẽ không đề cập đến bất kỳ kỹ
thuật lập trình C++ nào cả, mà tập trung vào hướng dẫn phong cách
lập trình.
Các IDE có thể cải thiện khả năng đọc mã nguồn
thông qua khả năng nhảy con trỏ (đến các hàm, biến trong chương trình),
thay đổi màu từ khóa, tự động điền… vân vân…. tuy nhiên các lập trình
viên không nên phụ thuộc vào những tiện ích này. Mã nguồn không phải
lúc nào cũng được đọc bằng một IDE nhất định, nó cần được phát
triển độc lập và tối đa hóa khả năng đọc mã nguồn trên bất kỳ công
cụ nào.
Những quy tắc này có kèm theo một số ví dụ để người đọc để hiểu và dễ vận dụng. Trong các dự án thực thường xảy ra vấn đề pha trộn giữa ngôn ngữ bình thường và ngôn ngữ kỹ thuật gây khó hiểu, tài liệu này sẽ không đề cập đến bất kỳ kỹ thuật lập trình C++ nào cả, mà tập trung vào hướng dẫn phong cách lập trình.
1. Hướng dẫn đọc
Các quy tắc được gom nhóm theo chủ đề và được đánh
số để tiện đọc.
Các quy tắc được trình bày như sau:
Trình bày ngắn gọn về quy
tắc này.
|
Ví dụ (nếu có)
|
Lý do nên dùng, bối cảnh dùng và các thông tin thêm.
|
Cần chú ý phần Lý do, các tiêu chuẩn này có thể
khác nhau trong các môi trường, văn hóa, ngôn ngữ khác nhau.
2. Chú ý quan trọng
Bạn nên chú ý các từ khóa “phải, nên, có thể”,
“phải” đại diện cho một quy tắc bạn phải tuân thủ theo, “nên” là các
quy tắc được khuyến cáo nên dùng, và “có thể” là các hướng dẫn
chung, gợi ý.
B.Các quy tắc chung
Được phép vi phạm mọi quy
tắc của tài liệu này nếu nó cải thiện khả năng đọc mã của bạn.
|
Mục tiêu chính của tài liệu là gia tăng khả năng đọc mã cho
lập trình viên để gia tăng sự thông hiểu đối với mã nguồn và khả năng
chỉnh sửa, bảo trì mã nguồn đó. Bộ quy tắc này không thể bao hàm
tất cả các trường hợp, nên lập trình viên cũng cần linh hoạt tiếp
thu theo môi trường học tập và làm việc.
|
Được phép vi phạm mọi quy
tắc nếu có sự phản đối nào đó mà bạn phải tuân thủ.
|
Mục đích của người biên soạn là tạo ra một hướng dẫn, không
phải để ép buộc người đọc sử dụng một phong cách mang tính cá
nhân, dù sao thì các lập trình viên có kinh nghiệm có thể sẽ muốn
áp dụng những quy tắc khác, nhưng có một điều, ít nhất bạn hãy làm
quen với quy tắc này, để bạn có thể bắt đầu làm quen với vấn đề phong cách lập trình và bước đầu tìm ra thói quen
của mình khi lập trình.
Mặt khác, các lập trình viên chưa có kinh nghiệm cũng nên sử
dụng một phong cách để tiện lợi hơn trong việc lập trình và đặt
tên.
|
C. Quy ước đặt tên
1. Quy ước đặt tên chung
Tên của các kiểu dữ liệu
(class, struct, enum…) phải viết hoa chữ cái đầu tiên của mỗi từ.
|
Line, SavingAccount
|
Quy tắc này đã khá phổ biến trong cộng đồng lập trình C++.
|
Tên biến phải bắt đầu với
chữ cái thường và viết hoa chữ cái đầu của các từ sau.
|
line, savingAccount
|
Khá phổ biến, quy tắc này giúp phân biệt biến và kiểu dữ
liệu và có tác dụng giải quyết lỗi trong khai báo: Line line;
|
Tên của các hằng (kể cả
các giá trị của kiểu enum) phải viết hoa toàn bộ, sử dụng dấu
gạch dưới để phân biệt các từ.
|
MAX_ITERATION, COLOR_RED, PI
|
Khá phổ biến trong cộng đồng C++. Tuy nhiên, nên giảm thiểu
việc sử dụng các hằng số như vậy, thay vào đó tạo lập một hàm
lấy về giá trị sẽ tốt hơn:
int getMaxIterations() //THAY
CHO: MAX_ITERATIONS = 25
{
return 25;
}
Kiểu hàm này vừa dễ đọc vừa đảm bảo sự thống nhất
về Interface đối với các giá trị
trong class.
|
Tên của các hàm phải bắt
đầu bằng động từ và chữ cái đầu tiên phải viết thường.
|
getName(), computeTotalWidth()
|
Khá phổ biến trong cộng đồng C++. Khá giống tên biến, nhưng
rất dễ dàng để phân biệt hàm với biến trong C++. Trong trường hợp
lấy địa chỉ hàm, thì ta cũng dễ dàng thấy tên hàm luôn bắt đầu
với động từ còn tên biến là tính từ hoặc danh từ.
|
Tên của namespace phải ghi
thường toàn bộ.
|
model::analyzer, io::iomanager, common::math::geometry
|
Đã khá phổ biến trong cộng đồng C++.
|
Tên của các lớp mẫu trong
template phải là một ký tự hoa duy nhất.
|
template<class T>....template<class C, class
D>....
|
Khá phổ biến, cách đặt tên này giúp tên của các lớp mẫu
nổi bật lên giữa các tên khác.
|
Các chữ cái trong những
từ viết tắt không được viết hoa toàn bộ khi dùng để đặt tên.
|
exportHtmlSource(); //THAY
CHO: exportHTMLSource();
openDvdPlayer(); //THAY
CHO: openDVDPlayer();
|
Dùng chữ viết hoa cho các từ viết tắt sẽ gây mâu thuẫn với
các quy tắc trên, những biến kiều này có thể đặt tên kiểu dVD, hTML
nhưng sẽ khá khó đọc, hơn nữa rất khó phân biệt khi ta đặt những
tên có nhiều từ (như trên) và các từ viết hoa bị nối liền với
nhau.
|
Các biến toàn cục phải
luôn được gọi bằng toán tử quan hệ (::)
|
::mainWindows.open(), ::applicationContext.getName()
|
Tuy nhiên nên hạn chế sử dụng biến toàn cục, thay vào đó
hãy sử dụng singleton pattern.
|
Thuộc tính của các lớp
nên có dấu gạch dưới sau tên.
|
class SomeClass { private: int length_;}
|
Ngoài tên và loại của thuộc tính thì phạm vi của biến là
một điều quan trọng cần lưu ý. Quy tắc này giúp người đọc mã dễ
dàng phân biệt các biến thuộc quyền quản lý của lớp đang viết và
các biến trong hàm. Thuộc tính của lớp được đánh giá là quan
trọng hơn so với các biến khác trong hàm, và đánh dấu như vậy, lập
trình viên sẽ dễ dàng nhận ra chúng để “chăm sóc đặc biệt”.
Một tác dụng khác nữa là cách đặt tên này sẽ giải quyết
vấn đề trùng tên của hàm set một cách nhanh gọn và đỡ nhức đầu:
void setDepth(int depth)
{
depth_ = depth;
}
Một vấn đề nữa là liệu dấu gạch chân nên được thêm vào
trước hay sau tên thuộc tính. Thực ra cả 2 cách này đều thường được
sử dụng, nhưng đặt gạch dưới sau tên được khuyến khích hơn vì nó
ít ảnh hưởng hơn đến việc đọc và gõ tên biến.
Lưu ý rằng: việc đặt các ký hiệu xác định phạm vi trong tên
biến vẫn còn một số tranh cãi, nhưng quy ước này vẫn đang dần được
chấp nhận và ngày càng phổ biến hơn trong các môi trường chuyên
nghiệp.
|
Các biến chung (Generic
variables) nên đặt tên giống với kiểu của chúng.
|
void setTopic(Topic* topic) // NOT: void setTopic(Topic*
value)
//
NOT: void setTopic(Topic* aTopic)
//
NOT: void setTopic(Topic* t)
void connect(Database* database) // NOT: void
connect(Database* db)
//
NOT: void connect (Database* oracleDB)
|
Giảm độ phức tạp bằng cách giảm số lượng tên sử dụng, hơn
nước quy ước này làm cho người lập trình dễ dàng liên tưởng đến
kiểu dữ liệu của biến.
Nếu vì lý do nào đó mà quy ước này “có vẻ không phù hợp”
thì đó là dấu hiệu của việc đặt tên kiểu không phù hợp.
Những biến không chung là những biến giữ một vai trò nào
đó, hay có nhiều biến cùng kiểu trong đoạn chương trình. Các biến
này thường được đặt tên bằng cách kết hợp vai trò của biến và tên
kiểu dữ liệu.
Point startingPoint,
centerPoint;
Name loginName;
|
Tên biến phải được đặt
bằng tiếng Anh.
|
fileName; //NOT:tenfile
|
Tiếng Anh là ngôn ngữ ưu tiên trong lập trình, vì có khả năng
phát triển quốc tế.
|
Phân biệt phạm vi của biến
dựa theo độ dài của tên.
|
Các biến có phạm vi sử dụng rộng nên được đặt tên dài hơn
các biến có phạm vi nhỏ, theo quy ước này, người lập trình có thể
giả định được một số biến chỉ sử dụng trong một số dòng lệnh
nhất định. Những cái tên phổ biến cho các biến số nguyên cục bộ
là i,j,k,m,n và cho ký tự là c,d.
|
Nên tránh đặt tên hàm có
từ đại diện được cho đối tượng.
|
line.getLength(); // NOT: line.getLineLength();
|
Đặt tên như vậy khiến tên hàm có vẻ tự nhiên, tuy nhiên điều
đó không cần thiết (như ví dụ).
|
2. Quy ước đặt tên cụ thể.
Phải sử dụng bộ hàm
get/set khi truy cập trực tiếp đến thuộc tính của đối tượng.
|
employee.getName();
employee.setName(name);
matrix.getElement(2, 4);
matrix.setElement(2, 4, value);
|
Thuật ngữ compute nên được dùng để đặt tên
cho các hàm tính toán.
|
valueSet->computeAverage();
matrix->computeInverse()
|
Làm người đọc ngay lập tức nhận ra đây là thao tác cần
nhiều thời gian nếu gọi nhiều lần, trong trường hợp đó, lập trình viên
có thể xem xét việc lưu kết quả vào bộ nhớ đệm. Sử dụng bộ hàm
này sẽ khiến mã dễ đọc hơn. (Trường hợp thao tác với nhiều lớp)
|
Thuật ngữ find nên được dùng để đặt tên cho
các hàm tìm kiếm.
|
vertex.findNearestVertex();
matrix.findMinElement();
|
Giúp người đọc dễ dàng nhận ra đây là một hàm tìm kiếm
thông thường với các phép tính đơn giản bên trong. Khiến mã dễ đọc
hơn.
|
Tiền tố initialize có thể được dùng để đặt tên cho các hàm thiết
lập đối tượng.
|
printer.initializeFontSet();
|
initialize (Anh – Mỹ) thường được dùng hơn initialise (Anh –
Anh). Nên tránh tên viết tắt init.
|
Biến đại diện cho các đối
tượng trên giao diện người dùng nên có hậu tố là tên kiểu dữ liệu
của đối tượng.
|
mainWindow, propertiesDialog, widthScale, loginText,
leftScrollbar, mainForm, fileMenu, minLabel, exitButton, yesToggle...
|
Giúp người đọc mã dễ dàng nhận ra kiểu dữ liệu và các
nguồn tài nguyên đối tượng sử dụng.
|
Nên dùng dạng số nhiều
của từ để đặt tên cho các biến có thể lưu trữ nhiều đối tượng.
|
vector<Point> points;
int values[];
|
Cho người đọc mã biết đây là một tập hợp các phần tử, có
thể sử dụng toán tử lấy phần tử ([]) và thao tác lên các phần tử
đó.
|
Nên đặt n trước các biến
biểu thị tổng số lượng.
|
nPoints, nLines
|
Quy ước này tương tự như Toán, dùng để chỉ các biến lưu trữ
số lượng của thứ gì đó.
|
Nên đặt tên các biến đếm
là i,j,k…
|
for (int i = 0; i < nTables); i++) {
:
}
for (vector<MyClass>::iterator i = list.begin(); i
!= list.end(); i++) {
Element element =
*i;
...
}
|
Quy ước này cũng lấy từ toán học, để chỉ ra đây là các
biến đếm của vòng lặp.
|
Nên đặt is trước tên của các biến hoặc hàm logic.
|
isSet, isVisible, isFinished, isFound, isOpen
|
Đã phổ biến trong cộng dồng C++ và một phần của cộng đồng
Java.
Sử dụng tiền tố is
giúp lập trình viên giải quyết vấn đề lựa chọn tên cho các biến
logic, tránh được các tên gây khó hiểu như status hoặc flag.isStatus hoặc
isFlag.
Thực ra ngoài is ta có
thể lựa chọn một số tiền tố khác tùy theo trường hợp:
bool hasLicense();
bool canEvaluate();
bool shouldSort();
|
Phải dùng đúng tên cho các
bộ hàm bổ sung.
|
get/set, add/remove, create/destroy, start/stop,
insert/delete, increment/decrement, old/new, begin/end, first/last, up/down,
min/max, next/previous, old/new, open/close, show/hide, suspend/resume.....
|
Đơn giản hóa việc đặt tên cho các hàm có chức năng ngược
nhau.
|
Nên tránh các từ viết tắt
khi đặt tên.
|
computeAverage(); // NOT: compAvg();
|
Việc này cũng phân ra 2 nhóm từ:
-Nhóm thứ nhất – từ nguyên bản dễ gợi nhớ hơn từ viết tắt,
nhóm này nên sử dụng các từ nguyên bản:
cmd -> command
cp -> copy
pt -> point
comp -> compute
init -> initialize….
-Nhóm thứ 2 – từ viết tắt được biết đến nhiều hơn và dễ
gợi nhớ hơn từ gốc, nhóm này nên sử dụng các từ viết tắt:
HypertextMarkupLanguage
-> html
CentralProcessingUnit
-> CPU
PriceEarningRatio -> pe
|
Nên tránh sử dụng các từ
ám chỉ con trỏ để đặt tên cho con trỏ.
|
Line* line; //NOT:
Line* pLine
//NOT:
Line* linePtr
|
Rất nhiều biến trong môi trường C/C++ là con trỏ nên ta gần
như không thể tìm ra đủ tiền tố hay hậu tố cho các con trỏ. Ngoài
ra mỗi đối tượng trong chương trình đều có một chức năng riêng,
người lập trình sẽ theo chức năng để thao tác nên các tiền tố (hậu tố) này không cần thiết. Chỉ nên
nhấn mạnh kiểu của biến con trỏ khi nó có ý nghĩa đặc biệt.
|
Không nên đặt isNot hoặc isNo trước các tên (biến hoặc hàm) logic.
|
bool isError; // NOT: isNoError
bool isFound; // NOT: isNotFound
|
Cách đặt tên này gây khó khăn cho người đọc mã nếu trong mã
nguồn của bạn xuất hiện vấn đề phủ định 2 lần một đối tượng nào
đó. Ví dụ như: !isNotFound.
|
Các giá trị của kiểu enum có thể bắt đầu bởi một từ
đặc trưng cho kiểu.
|
enum Color { COLOR_RED, COLOR_GREEN, COLOR_BLUE };
|
Cách viết này cho người đọc thông tin về kiểu dữ liệu của
giá trị - nơi mà các giá trị tương tự được định nghĩa.
Một cách khác là luôn sử dụng tên kiểu để gọi giá trị:
Color::RED. Airline::AIR_FRANCE…
Một lưu ý khác: tên của kiểu dữ liệu enum nên đặt ở số ít,
ví dụ như Color. Sử dụng dạng số nhiều như Colors có thể không ảnh
hưởng gì tuy nhiên dễ gây bối rối khi sử dụng, vì ta chỉ gọi một
giá trị trong enum cho mỗi lần gọi tên lớp.
|
Các lớp định nghĩa biệt
lệ nên có đuôi là Exception.
|
class AccessException{...}
|
Các lớp biệt lệ không nằm trong phạm vi chương trình, nên đặt
tên kiểu này sẽ giúp chúng nổi bật hơn.
|
Các hàm/phương thức nên được
đặt tên theo kết quả trả về (functions) hoặc chức năng của chúng
(procedures).
|
Giúp lập trình viên dễ nhận ra chức năng và cách sử dụng
của các hàm/thủ tục, qua đó tránh được các “tác dụng phụ” từ
hàm/thủ tục.
|
D. Tập tin
1. Các tập tin mã nguồn
Các file header nên có phần
mở rộng .h hoặc .hpp, còn các tập tin mã nguồn nên có đuôi
.c++/.c/.cc/.cpp
|
MyClass.c++, MyClass.h
|
Tất cả những phần mở rộng này đều được C++ chấp nhận.
|
Một lớp nên được khai báo
ở một file header và định nghĩa ở một file mã nguồn cùng tên.
|
MyClass.h, MyClass.c++
|
Giúp dễ dàng tìm kiếm các file liên kết với một lớp nào
đó. Tuy nhiên, có một ngoại lệ, đó là các lớp khuôn mẫu (template)
phải được khai báo và định nghĩa trong cùng 1 file.
|
Tất cả các định nghĩa phương
thức của một lớp phải được đặt trong cùng một tập tin.
|
class MyClass {
public: int getValue () {return value_;} // NO!
... private: int value_;
.
.
};
|
Các file header chỉ bao gồm các khai báo, file mã nguồn mới
là file định nghĩa các phương thức (ngoại trừ trường hợp template).
Một định nghĩa phương thức dù ngắn đến đâu cũng phải nằm trong file
mã nguồn của lớp.
|
Các câu lệnh phải ngắn,
mỗi dòng chỉ được phép có 80 kí tự trở xuống tính từ lề trái
của file.
|
80 kí tự là quy ước chung cho các trình soạn thảo, in ấn và
debug, hơn nữa các tập tin này được chia sẻ giữa nhiều lập trình
viên nên giữ cho dòng lệnh không quá dài sẽ giúp người đọc mã dễ
dàng tiếp thu hơn.
|
Phải tránh các ký tự đặc
biệt như Tab hay ngắt trang.
|
Các kí tự này dễ gây ra xung đột với các chương trình chỉnh
sửa, in ấn, các trình giả lập và debug khi chương trình được phát
triển theo nhiều công đoạn, bởi nhiều lập trình viên, trên nhiều nền
tảng.
|
Các dòng lệnh phải được
phân chia rõ ràng.
|
totalSum = a + b + c +
d + e;
function (param1, param2,
param3);
setText ("Long line split"
"into
two parts.");
for (int tableNo = 0; tableNo < nTables;
tableNo +=
tableStep) {
...
}
|
Khi các dòng lệnh có nhiều hơn 80 kí tự thì chúng cần được
chia thành nhiều dòng. Thực tế không có một quy định nào rõ ràng
về việc chia dòng, nhưng thông thường, chúng ta nên đảm bảo các điều
kiện sau:
-
Ngắt dòng sau dấu phẩy (hoặc một toán
tử).
-
Hàng mới bắt đầu tại vị trí ngang với
điểm bắt đầu danh sách đối số hoặc điểm bắt đầu tính toán của
hàng trên.
-
Trường hợp xảy ra ngắt dòng lệnh phải
thêm 1 khoảng trống giứa dòng lệnh vừa ngắt và dòng tiếp theo đó.
|
2. Khai báo và include thư viện.
Các file header (.h) phải
chứa “khóa bảo vệ trùng file”.
|
#ifndef COM_COMPANY_MODULE_CLASSNAME_H
#define COM_COMPANY_MODULE_CLASSNAME_H
:
#endif // COM_COMPANY_MODULE_CLASSNAME_H
|
Các khóa này nhằm bảo vệ chương trình khỏi các lỗi biên
soạn. Khóa này nhằm định danh cho mã nguồn nằm bên trong khóa, qua
đó tránh được lỗi về xung đột mã nguồn khi một hoặc nhiều đoạn
mã được biên soạn lại.
|
Các khối include nên được
phân loại và sắp xếp, sắp xếp theo sự phân cấp về vị trí, và các
thư viện cơ sở nên được include trước. Đặt một khoảng trắng giữa
các cấp.
|
#include <fstream>
#include <iomanip>
#include <qt/qbutton.h>
#include <qt/qtextfield.h>
#include "com/company/ui/PropertiesDialog.h"
#include "com/company/ui/MainWindow.h"
|
Ngoài ra để người đọc dễ hình dung, các directive include
cũng cho phép người lập trình truyền vào đường dẫn đến thư viện
được sử dụng.
Tránh sử dụng các đường dẫn tuyệt đối. Thay vì truyền vào
file gốc chứa các thư viện được sử dụng, ta nên chỉ ra cụ thể các
thư viện được sử dụng trong project.
|
Các Directive include phải
được đặt ở đầu các file.
|
Nhằm tránh các lỗi không mong muốn, gây ra bởi các lệnh
include nằm ẩn sâu trong mã nguồn.
|
E. Khai báo
1. Về khai báo.
Loại khai bảo sử dụng
trong 1 file thì chỉ có thể được khai báo trong chính file đó.
|
Tính bảo mật dữ liệu.
|
Các phần của một class
phải được sắp xếp theo thứ tự: public – protected – private.
|
Thiết lập trật tự cho các phần của class, người dùng có
thể dừng đọc class khi lăn đến khu vực không được thao tác.
|
Luôn sử dụng khai báo ép
kiểu một cách rõ ràng. Không bao giờ sử dụng ép kiểu “ngầm”.
|
floatValue = static_cast<float>(intValue);
// NOT: floatValue = intValue;
|
Bằng cách này, người lập trình chỉ ra được rằng: hai kiểu
dữ liệu này ít nhiều có sự liên quan với nhau, và sự chuyển đổi
này là có chủ ý.
|
2. Về biến.
Các biến nên được khởi
tạo ngay tại nơi chúng được khai báo.
|
Điều này đảm bảo rằng biến luôn tồn tại giá trị phù hợp.
Đôi khi ta không thể khởi tạo giá trị cho biến ngay khi khai báo, như
ví dụ:
int x, y, z;
getCenter(&x, &y, &z);
Trong những trường hợp này, tốt hơn ta nên đặt giá trị rỗng
cho biến chứ không nên tạo giá trị giả.
|
Biến phải đơn nghĩa.
|
Khiến mã nguồn dễ đọc hơn, một biến chỉ đại diện cho một
khái niệm duy nhất, với một tác dụng duy nhất. Tránh được một số
lỗi khi chuyển đổi công dụng của biến.
|
Nên hạn chế việc sử dụng
biến toàn cục (global).
|
Trong C++ thì không có lý do gì để người lập trình buộc
phải lựa chọn biến toàn cục cả. Điều này cũng tương tự đối với
các hàm toàn cục và các khối biến toàn cục.
|
Thuộc tính của lớp không
được khai báo công khai (public).
|
Việc khai báo thuộc tính ở phạm vi public sẽ vi phạm các quy
phạm về tính đóng gói và mã hóa dữ liệu của C++. Thay vào đó, ta
nên sử dụng các thuộc tính private và các hàm truy cập kèm theo.
Quy tắc này có một ngoại lệ, đó là khi ta khai báo một lớp như
một cấu trúc dữ liệu, không có bất kỳ phương thức nào (tương đương
với Struct).
Lưu ý rằng: struct được giữ lại trong C++ chỉ để tương thích
với C, tránh sử dụng sẽ giúp mã nguồn dễ đọc hơn (do giảm số
lượng các cấu trúc sử dụng), thay cho struct, trong C++ ta nên dùng
class.
|
Dấu hiệu con trỏ và tham
chiếu trong C++ nên được đặt gần tên biến khi khai báo.
|
float* x; // NOT: float *x;
int& y; //
NOT: int &y;
|
Con trỏ và tham chiếu của một biến giống một thuộc tính
trong kiểu hơn là tên một biến. Lập trình viên C thường sử dụng các
tên thay thế gần nghĩa, trong khi đó, C++ thường sử dụng quy chuẩn
này.
|
Các toán tử ngầm định
với 0 không nên được sử dụng khi kiểu dữ liệu không phải boolean.
|
if (nLines != 0)
// NOT: if (nLines)
if (value != 0.0) // NOT: if (value)
|
C++ tiêu chuẩn không nhất thiệt định nghĩa số nguyên hay số
thực với giá trị 0 là dãy bit 0. Hơn nữa, bằng cách sử dụng một
toán tử so sánh rõ ràng sẽ giúp người đọc nhanh chóng nhận biết
kiểu dữ liệu của biến được so sánh.
|
Nên khai báo phạm vi tồn
tại của biến càng nhỏ càng tốt.
|
Việc giới hạn phạm vi tồn tại của biến thật nhỏ sẽ giúp
người lập trình tránh được những tác dụng không mong muốn.
|
3. Về vòng lặp.
Chỉ duy nhất biến kiểm
soát vòng lặp mới phải đưa vào cặp () của vòng lặp for.
|
sum = 0;
// NOT: for (i = 0, sum = 0; i < 100; i++)
for (i = 0; i < 100; i++) sum += value[i];
sum += value[i];
|
Phân biệt được biến quản lý và các biến xử lý trong vòng
lặp, hỗ trợ lập trình viên đọc và bảo trì mã nguồn.
|
Biến xử lý trong vòng lặp
nên được khởi tạo ngay trước vòng lặp.
|
isDone = false;
// NOT: bool isDone = false;
while (!isDone) {
// : //Many line
://Many line // while (!isDone) {
}
// : //Many line
// }
|
Có thể tránh các vòng
lặp do-while.
|
Vòng lặp do-while khó đọc hơn vòng while hay for thông thường,
do điều kiện của các kiểu vòng lặp này được đặt ở đầu vòng lặp.
Khi sử dụng do-while, người đọc phải đọc vào vòng lặp để hiểu cơ
chế và điều kiện dừng của vòng lặp .
Thêm vào đó, ta không nhất thiết phải sử dụng vòng do-while,
bất kỳ vòng do-while nào cũng có thể dễ dàng viết lại thành vòng
while hay vòng for. Giảm số lượng cấu trúc sử dụng khi lập trình
sẽ giúp mã nguồn đơn giản và dễ đọc hơn.
|
Nên tránh sử dụng break và continue trong vòng lặp.
|
Các từ khóa này chỉ nên được sử dụng trong các trường hợp
ngoại lệ – khiến mã nguồn dễ đọc hơn.
*Đa phần sẽ khiến vòng lặp phức tạp hơn. |
Nên dùng cấu trúc while(true) cho các vòng lặp vô
hạn.
|
while (true) {
:
}
for (;;) { // NO!
:
}
while (1) { // NO!
:
}
|
Điều kiện kiểm tra là 1 sẽ không bao hàm đủ ý nghĩa, bên
cạnh đó, dạng for(;;) lại chẳng dễ đọc tí nào, và cả 2 kiểu cấu
trúc này đều không thể hiện rằng đó là một vòng lặp vô hạn.
|
4. Về cách đặt điều kiện.
Phải tránh các khối điều
kiện phức tạp. Sử dụng biến bool để chia nhỏ điều kiện ra nếu nó
quá rườm rà.
|
bool isFinished = (elementNo < 0) || (elementNo >
maxElement);
bool isRepeatedEntry = elementNo == lastElement;
if (isFinished || isRepeatedEntry) {
:
}
// NOT:
if ((elementNo < 0) || (elementNo > maxElement)||
elementNo ==
lastElement) {
:
}
|
Nhờ việc phân tích điều kiện ra nhiều biến boolean, các điều
kiện sẽ trở nên dễ đọc, dễ bảo trì và sửa lỗi.
|
Các điều kiện kiểm tra sự
tồn tại của một đối tượng nào đó nên được đặt vào if và đặt biệt lệ tương ứng vào else.
|
bool isOk = readFile (fileName);
if (isOk) {
:
}
else {
:
}
|
Đảm bảo rằng các biệt lệ có thể xảy ra sẽ không gây khó
khắn cho việc thực hiện chương trình. Quy tắc này khá quan trọng
trong việc khiến mã nguồn dễ đọc hơn và gia tăng hiệu suất chương
trình.
|
https://www.facebook.com/tuan.tranminh.7334
http://www.stdio.vn/users/index/95/tuan-tran
Nhận xét
Đăng nhận xét