Mar 11, 2009

Effective C++ [phần 1] - Giới thiệu

Giới thiệu
cuốn Effective C++ của tác giả Scott Meyers. Sứng đáng là một cuốn sách gối đầu giường của những người lập trình C++. Về tác giả sách này theo người viết được biết ông còn viết 1 quyển khác cũng rất có giá trị với người yêu thích làm việc với C++ đó là cuốn More effectve C++ như là phần 2 của cuốn sách này. Ngoài ra còn một cuốn sách tham khảo khác về STL cũng rất có giá trị trong thế giới sách về C++ là cuốn Effective STL.

Thuật ngữ
Đây là một phần nhỏ trong từ vựng mà tất cả những lập trình viên đều phải hiểu. Dưới đây là những nhóm khá quan trọng mà chúng ta phải hiểu ngữ nghĩa của chúng.
Một khai báo thông báo cho trình biên dịch biết tên và kiểu của một cái gì đó, đây là những khai báo

extern int x; // object declaration

std::size_t numDigits(int number); // function declaration

class Widget; // class declaration

template<typename ...> // template declaration
class GraphNode; // (see Item 42 for info on
// the use of "typename")

Hãy chú ý là biến x kiểu interger là một đối tượng, mặc dù nó là kiểu build-in (xây dựng sẵn). Một vài người vẫn dè dặt với từ “Đối tượng” cho những biến của kiểu người dùng định nghĩa (user-define type). Ngoài ra cũng cần chú ý thêm rằng chức năng numDigits trả về một kiểu std::size_t kiểu size_t trong namespace std, Đây là một namespace chứa đựng tất cả những thư viện chuẩn của C++ cục bộ. Tuy nhiên vì chuẩn C (thường gọi là C89) cũng có thể sử dụng trong C++ vì thế cái được kế thừa từ C (kiểu như size_t) cũng tồn tại ở phạm vi toàn cục hoặc trong std hoặc cả hai. Điều này phụ thuộc vào file header trong #include mà bạn gọi. Về mặt sử dụng nói chung thì tuỳ bạn nhưng tôi khuyến cáo các bạn nên sử dụng chuẩn std cho các thành phân trong namesapce này.
Size_t theo cách này chỉ là một typedef cho một kiểu không dấu mà C++ sử dụng khi đếm một cái gì đó (ví dụ như số ký tự trong một char* của một string hoặc những thực thể của một STL container). Nó cũng có thể là kiểu được quy chiếu bởi hàm operator[] trong vectorm, deque string. Một thoả thuận là chúng ta sẽ định nghĩa lại trong mục 3.

Mỗi một chức năng khai báo sẽ biểu lộ một chữ ký, một chữ ký được đánh dấu bởi tham số và kiểu trả về, đối với hàm numDigits chữ ký là cần một tham số kiểu int và chả về kiểu std::size_t trong chuẩn C++ ngăn chặn kiểu trả về nhưng với cuốn sách này kiểu chả về là một tiện ích của chữ ký.

Một definetion – định nghĩa cung cấp cho trình biên dịch những chi tiết của một khai báo. Với một đối tượng định nghĩa là nơi để trình biên dịch dành bộ nhớ cho đối tượng. Với một hàm hoặc một hàm mẫu, định nghĩa cung cấp thân của mã lệnh. Với một lớp hoặc một lớp mẫu định nghĩa cung cấp một danh sách các thành phần của lớp hoặc của mẫu.

int x; // object definition

std::size_t numDigits(int number) // function definition.
{ // (This function returns
std::size_t digitsSoFar = 1; // the number of digits
// in its parameter.)
while ((number /= 10) != 0) ++digitsSoFar;
return digitsSoFar;
}

class Widget { // class definition
public:
Widget();
~Widget();
...
};

template<> // template definition
class GraphNode {

public:

GraphNode();

~GraphNode();

...

};

Initialization – cài đặt là một tiến trình đưa vào những giá trị đầu tiên cho đối tượng, Với đối tượng là một kiểu dữ liệu người dùng định nghĩa. Cài đặt được sử lý bởi hàm tạo. Một hàm tạo mặc định defualt-contructor là một hàm tạo không tham số hoặc hàm khởi tạo với giá trị mặc định cho những tham số.

class A {
public:
A(); // default constructor
};

class B {
public:
explicit B(int x = 0, bool b = true); // default constructor; see below
}; // for info on "explicit"

class C {
public:
explicit C(int x); // not a default constructor
};

Hàm khởi tạo cho lớp B và C ở đây được khai báo là explicit, nó sẽ ngăn chặn việc sử dụng chuyển kiểu ngầm định, mặc dù chúng vẫn có thể được sử dụng cho việc chuyển kiểu tường minh.

void doSomething(B bObject); // a function taking an object of
// type B

B bObj1; // an object of type B

doSomething(bObj1); // fine, passes a B to doSomething

B bObj2(28); // fine, creates a B from the int 28
// (the bool defaults to true)

doSomething(28); // error! doSomething takes a B,
// not an int, and there is no
// implicit conversion from int to B

doSomething(B(28)); // fine, uses the B constructor to
// explicitly convert (i.e., cast) the
// int to a B for this call. (See
// Item 27 for info on casting.)

Hàm khởi tạo với khai báo explicit thông thường thích hợp với những trương hợp không rõ ràng về kiểu, bởi vì chúng ngăn không cho trình biên dịch sử lý những tình huống bất ngờ, không nhắm tơi trong việc chuyển đổi kiểu. Trừ phi bạn có một lý do sách đáng cho việc chuyển đổi kiểu mặc định. Khuyến cáo nên sử dụng !

Copy – contructor Một hàm tạo sao chép dùng để cài đặt một đối tượng với một đối tượng khác cùng kiểu. còn toán tử gán và sao chép được sử dụng để sao chép từ một đối tượng khác có cùng kiểu.

class Widget {
public:
Widget(); // default constructor
Widget(const Widget& rhs); // copy constructor
Widget& operator=(const Widget& rhs); // copy assignment operator
...
};
Widget w1; // invoke default constructor

Widget w2(w1); // invoke copy constructor

w1 = w2; // invoke copy
// assignment operator

Hãy đọc cẩn thận khi bạn đọc thấy sự xuất hiện của một phép gán. Bởi vì cú pháp của “=” có thể gọi tới một hàm khởi tạo sao chép.

Widget w3 = w2; // invoke copy constructor!

Thật may nắm vì hàm tạo sao chép thật dễ dàng để phân biệt với sao chép gán. Nếu một đối tượng mới được định nghĩa thì nó sẽ gọi đến hàm tạo sao chép (giống như w3 ở trên) chính vì thế một hàm khởi tạo sẽ được gọi. Nếu không có một đối tượng mới nào được tạo thì nó chỉ đơn thuần là một phép gán (giống như w1 & w2)

Hàm khởi tạo sao chép là một chức năng đặc biệt quan trọng bởi vì nó sẽ định nghĩa như thế nào một đối tượng được chuyền bởi giá trị ví dụ:

bool hasAcceptableQuality(Widget w);
...
Widget aWidget;
if (hasAcceptableQuality(aWidget)) ...

Tham số w được chuyền cho hàm hasAcceptableQuality là một giá trị (tham chị) vì thế khi được gọi như ở trên thì aWidget sẽ được sao chép cho w sự sao chép được làm bởi hàm khởi tạo sao chép của Widget. Như thế chuyền bởi giá trị có nghĩa là “gọi hàm khởi tạo sao chép” (Tuy nhiên đây là một ý tưởng tồi tệ không nên dùng tốt nhất nên chuyền theo kiểu hằng tham số mục 20)

STL - Standard Template Library là thư viện mẫu chuẩn. Một phần trong thư viện chuẩn đó cung cấp cho bạn những containers (vector,list…) iterators (vector::iterator, set::iterator… ) algorithms (for_each, find, sort…) và sự liên kết một lô những chức năng.
Có nhiều những chức năng thực hiện với đối tượng chức năng – một đối tượng hành động giống như một chức năng. Giống như những đối tượng từ lớp nạp chồng operator(), phương thức gọi toán tử. Nếu bạn không thân thiện với STL một cách tham chiếu nhanh nhất chính là đọc cuốn sách này. Bởi vì STL quá tiện ích đối với tôi (tác giả)

Lập trình đến với C++ từ Java hoặc C# sẽ hơi bị ngạc nhiên một chút bởi chú ý hành vi không định nghĩa. Cho một vài lý do hành động của hàm khởi tạo trong C++ rõ ràng là không định nghĩa. Bạn không thể chắc chắn được cái gì sẽ sảy ra vào lúc chạy ví dụ

int *p = 0; // p is a null pointer

std::cout << *p; // dereferencing a null pointer
// yields undefined behavior

char name[] = "Darla"; // name is an array of size 6 (don't
// forget the trailing null!)

char c = name[10]; // referring to an invalid array index
// yields undefined behavior

Để nhấn mạnh hành vi không định nghĩa không thể dự đoán và có rất nhiều những khó chụi. Những lập trình viên C++ nhiều kinh nghiệm thường nói rằng chương trình không định nghĩa dễ dàng điều khiển. Sự thật là chương trình không định nghĩa nó sẽ dễ dàng điều khiển, nhưng cũng không hẳn là vậy ! ??? (ứ hủi). Có nhiều khả năng hơn là chương trình sẽ sử lý một cách chập chờn…., “Effective C++ programmer” làm hết sức mình để hướng dẫn rõ ràng trong việc không định nghĩa. Một nhóm khác trong những ngôn ngữ lập trình đề cập đến là giao diện interface. Thông thường interfaces là một thực thể của ngôn ngữ lập trình, nhưng điều này không giống trong C++. Mục 33 sẽ thảo luận như thế nào để đánh giá được nó. Một client là một ai đó hoặc một điều gì đó sử dụng code của bạn viết.





No comments:

Post a Comment

 
Bạn có thể dùng bài viết của tôi tùy ý bạn nhưng vui lòng ghi lại rõ nguồn cung cấp
The world in a click_
Copyright © 2008 linhdkl