1. Struct
struct trong C++ không đơn thuần là một “gói” gồm nhiều biến mà chúng ta thường thấy, mà hơn thế nữa nó cũng có thể có các phương thức, với đầy đủ các tính chất đóng gói (encapsulation), kế thừa (inheritance), và đa hình (polymorphism) như class. Điểm khác biệt duy nhất để phân biệt giữa class với struct trong ngôn ngữ C++ là class có tầm vực mặc định (default accessibility) là private, trong khi đó đối với struct lại là public. Dưới đây là ví dụ đơn giản so sánh giữa class và struct trong C++:
class A
{
char* a; //default is private
int b; //default is private
public:
void function ();
A ();
~A ();
};
struct A
{
char* a; //default is public
int b; //default is public
private:
void function();
A ();
~A ();
};
2. Phương thức hằng
Từ khóa const không chỉ được dùng với các biến, hay các thuộc tính trong class, chúng ta còn có thể dùng từ khóa này cho các phương thức (cả ở phần khai báo & định nghĩa) như ví dụ dưới đây:
class Date {
public: // public interface:
enum Month { jan=1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec };
Date (int dd =0, Month mm =Month (0), int yy =0); // 0 means "pick a default"
// functions for examining the Date:
int day () const;
Month month () const; //use const in declaration
int year () const;
private:
int d;
Month m;
int y;
};
inline int Date::day () const //use const in definition
{
return d;
}
Khi một phương thức được khai báo với từ khóa này, phương thức đó sẽ đảm bảo không làm thay đổi giá trị các thuộc tính của đối tượng. Chính vì vậy chúng thường dùng để xuất giá trị hay thực hiện các phép tính toán từ các giá trị sẵn có của biến để lấy về một kết quả nào đó.
3. Helper function
Có một số trường hợp, class có một số các hàm liên kết với nó mà không cần phải định nghĩa bên trong class vì nó không cần truy cập trực tiếp đến thể hiện class. Ví dụ như:
int diff (Date a, Date b); // number of days in the range [a,b) or [b,a)
bool leapyear (int y);
Date next_weekday (Date d);
Date next_saturday (Date d);
Định nghĩa những hàm này bên trong class sẽ làm phức tạp thêm cho interface của class và tăng số lượng hàm tiềm tàng yêu cầu phải được xem xét khi cân nhắc việc thay đổi bên trong thể hiện class.
Có môt cách truyền thống để “liên kết” các hàm này với class Date là đặt các khai báo của chúng vào cùng 1 file với khai báo của class Date, và người dùng muốn sử dụng chúng thì sẽ include file định nghĩa interface của class. Ví dụ như "Date.h".
Chúng ta có thể liên kết tường minh giữa class và các helper function của nó bằng cách nhóm tất cả chúng vào một namespace như sau:
namespace Chrono {
// facilities for dealing with time
class Date { /* ... */};
int diff (Date a, Date b);
bool leapyear (int y);
Date next_weekday (Date d);
Date next_saturday (Date d);
// ...
}
namespace Chrono cũng sẽ chứa những class liên quan ví dụ như Time hay Stopwatch, và những helper function của chúng. Sử dụng namespace chỉ để bao chứa một class đơn lẻ thường sẽ gây ra bất tiện khi sử dụng.
4. Default constructor với thuộc tính hằng
Vì const và các tham chiếu cần phải được khởi tạo giá trị nên một class chứa các thuộc tính const hay tham chiếu không thể tự sinh một phương thức khởi tạo mặc định (default constructor), lập trình viên buộc phải định nghĩa tường minh chúng như ở ví dụ sau:
struct X
{
const int a;
const int &r;
};
X x;//error: no default constructor for X
5. Thành phần hằng
Có thể khởi tạo giá trị cho các thành phần hằng tĩnh (static integral constant member) bằng cách thêm khởi tạo constant-expression cho khai báo thành phần hằng. Ví dụ như sau:
class Curious {
public:
static const int c1 = 7; // ok, but remember definition
static int c2 = 11; // error: not const
const int c3 = 13; // error: not static
static const int c4 = f (17); // error: in-class initializer not constant
static const float c5 = 7.0; // error: in-class not integral
// ...
};
Nếu và chỉ nếu như sử dụng thành phần được khởi tạo giá trị theo cách yêu cầu chúng được lưu trữ dưới dạng một đối tượng trong bộ nhớ, các thành phần buộc phải được định nghĩa ở đâu đó. Việc khởi tạo giá trị có thể không bị lặp lại:
const int Curious::c1; // necessary, but don't repeat initializer here
const int* p = &Curious::c1; // ok: Curious::c1 has been defined
Một phương án khác để lựa chọn là sử dụng enum với vai trò là 1 hằng tượng trưng bên trong khai báo class như ở ví dụ dưới đây:
class X {
enum { c1 = 7, c2 = 11, c3 = 13, c4 = 17 };
// ...
};
(còn tiếp)
(Bài viết dựa trên sách The C++ Programming Language (Bjarne Stroustrup))