Viet Nam Community – Wander Man’s Blog

Có lẽ cách hiệu quả nhất để bắt đầu làm quen với một ngôn ngữ mới chính là bắt tay luôn vào việc viết chương trình với ngôn ngữ đó. Gần như chương trình nhập môn với bất cứ ngôn ngữ lập trình nào cũng là “Hello World”, nhưng mình sẽ biến thể nó đi một chút 😉 Bây giờ chúng ta sẽ xem xét một chương trình C++ đơn giản, chương trình “Hello Girl” :(|

// my first program in C++
#include 
using namespace std;

int main(){
    cout << “Hello, Girl” << endl;
    return 0;
}

Bây giờ chúng ta sẽ xem xét chi tiết từng dòng. Và mình sẽ giải thích tác dụng của mỗi dòng là gì. Những kiến thức này rất cơ bản, chỉ dành cho newbie. Nếu bạn nào đã học học qua ngôn ngữ C++ rồi thì có thể bỏ qua phần này :D

Dòng đầu tiên là một chú thích (comment). Tất cả những gì từ sau ký hiệu // đến hết dòng được hiểu là chú thích và bị trình biên dịch bỏ qua, hoàn toàn không gây ảnh hưởng gì đến hoạt động của chương trình. Mục đích duy nhất của chú thích là làm tăng tính sáng sủa của chương trình, ta dùng chú thích để giải thích ngắn gọn mục đích của đoạn code hay của chương trình là gì. Trong ví dụ này, chú thích cho biết đây là chương trình đầu tiên bằng C++ của tôi. Ta có thể chú thích trên nhiều dòng bằng cặp ký hiệu /* Here are your comments */. Tuy nhiên mình nghĩ dùng những chú thích ngắn gọn trên một dòng sẽ tốt hơn. Thêm nữa, chúng ta nên hạn chế sử dụng chú thích bừa bãi. Chỉ dùng khi thực sự cần thiết, và nên ngắn gọn, súc tích. Như vậy giúp ta trọng tâm hơn vào những phần chính và chương trình sẽ không bị rối. Hãy để các đoạn code tự nói lên ý nghĩa của chúng.

Dòng thứ hai là một chỉ thị tiền xử lý (preprocessor directive). Tất cả những gì bắt đầu bằng # đều là chỉ thị tiền xử lý và được xử lý bởi bộ tiền xử lý trước khi chương trình được dịch. Nó không phải là một câu lệnh (lưu ý mọi câu lệnh đều phải kết thúc bởi dấu chấm phẩy – semicolon ) mà là một chỉ thị hướng dẫn preprocessor nạp nội dung của tệp  vào. Việc này giống như ta copy toàn bộ nội dung của tệp  rồi paste vào đúng vị trí của chỉ thị #include . là một header file liên quan đến những thao tác nhập/xuất cơ bản. Nó chứa những khai báo (declarations) cần thiết cho nhập/xuất, ví dụ trong trường hợp này sẽ được dùng bởi cout và toán tử <<. Thiếu những khai báo này trình biên dịch sẽ không nhận ra cout và sẽ báo lỗi. Vì vậy cần thiết phải include . Chú ý: đôi khi ta thấy một số chương trình viết:

#include  

Trong khi 1 số ít chương trình lại viết :

#include 

Hai cách viết này là khác nhau. Những file có phần mở rộng .h là những file “cũ” có từ thời kỳ sơ khai của C++ và phần lớn trong số đó kế thừa và phát triển dựa trên các file của ngôn ngữ C. Khi ANSI ISO công bố chuẩn cho C++ thì các Standard Header File mới đều không có phần mở rộng. Nói chung thì New Standard Header File so với Classic Standard Header File không khác nhau nhiều lắm, cái sau cải tiến và hoàn thiện một số khiếm khuyết của cái trước. Tất nhiên là những cái gì theo chuẩn mới thì thông thường sẽ tốt hơn. Mình sẽ nói rõ hơn về phần này trong phần I/O stream.

Dòng thứ ba đề cập đến một khái niệm đó là “namespace” (đôi khi còn được gọi là name scope). Thông thường một chương trình có chứa nhiều định danh (identifiers) thuộc nhiều phạm vi (scope) khác nhau. Đôi khi một đối tượng trong phạm vi này bị trùng tên với một đối tượng khác trong một phạm vi khác. Điều này dẫn đến xung đột và gây lỗi biên dịch. Sự chồng chéo tên (identifier overlapping) có thể xảy ra ở nhiều cấp độ khác nhau, đặc biệt là trong các thư viện cung cấp bởi bên thứ ba. C++ Standard nỗ lực giải quyết vấn đề này bằng cách sử dụng namespace. Mỗi namespace xác định một phạm vi mà trong đó các định danh được nhận biết, ngoài phạm vi này chúng sẽ không được nhận biết. Để sử dụng một thành phần trong namespace ta có thể dùng câu lệnh như sau:

my_namespace::member;

Câu lệnh trên sử dụng một identifier có tên là member trong namespace có tên là my_namespace. Rõ ràng khi một namespace khác (ví dụ: your_namespace) cũng có một thành phần tên là member thì việc dùng hai tên này không sợ bị chồng chéo lên nhau. Toán tử :: là toán tử “phân giải phạm vi” (binary scope resolution operator). Trong câu lệnh trên toán tử :: cho biết rằng định danh member được sử dụng nằm trong phạm vi của namespace tên là my_namespace chứ không phải your_namespace. Quay trở lại chương trình của ta, nhận thấy trong hàm main, dòng thứ 5 có sử dụng cout endl. Đây là hai định danh được khai báo trong namespace std. Để chương trình “nhận biết” được cout endl thì ta có thể dùng cú pháp như vừa nói ở trên, tức dòng lệnh thứ 5 được viết lại là:

std::cout << “Hello, Girl” << std::endl;

Tuy nhiên, rõ ràng cách viết trên là dài dòng. Nếu ta sử dụng nhiều hơn các định danh trong namespace std thì mỗi lần dùng ta lại phải viết thêm std::, vì vậy để có thể sử dụng được toàn bộ các định danh trong namespace std ta dùng câu lệnh như dòng thứ 3:

using namespace std;

Những dòng còn lại là định nghĩa hàm main. Đây là hàm quan trọng nhất trong chương trình, có nhiệm vụ điều phối và kiểm soát toàn bộ chương trình, nó gọi những hàm khác khi cần thiết. Tuy nhiên mình muốn nói một điều hơi bất cập một tý. Khi mình đọc các tài liệu về C++ thì tất cả đều nói hàm main được gọi và xử lý trước mọi hàm khác trong chương trình. Điều này có luôn luôn đúng? Phần này mình nói hơi ngoài lề một tý, nó liên quan đến constructor của class nên nếu bạn nào chưa học đến phần này thì có thể bỏ qua. Xét một chương trình sau:

#include 
using namespace std;

// định nghĩa lớp My_class
class My_class{
    private:
        int number;
    public:
        My_class(){ number = 0; } // constructor
}

My_class global_var; // khai báo một biến toàn cục

// hàm main
int main(){
    cout << “Is main always called first ?” << endl;
    return 0;
}

Biến global_var được khai báo toàn cục bên ngoài tất cả mọi hàm. Khi khai báo biến global_var thì theo nguyên tắc phải gọi đến constructor của lớp My_class để khởi tạo number = 0. Vì vậy thực tế trong chương trình trên constructor My_class() được gọi trước main !


Bây giờ trở lại vấn đề chính, ta sẽ vẫn tiếp tục phân tích nốt mấy câu lệnh còn lại. Chúng ta để ý đến dòng thứ 6:

cout << “Hello, Girl” << endl;

Dòng này có tác dụng in dòng text nằm giữa hai dấy nháy kép, cụ thể là “Hello, Girl” lên màn hình. Chúng ta sẽ phân tích kỹ hơn một chút về nguyên tắc hoạt động của nó, tuy nhiên chỉ là một sự mô tả rất thô sơ. Để hiểu biết kỹ hơn chúng ta cần biết những kiến thức về đối tượng, quá tải toán tử, và nhiều vấn đề khác nữa. Trong C, để in một đoạn văn bản lên màn hình ta có thể dùng hàm printf. Điều này dễ làm cho ta lầm tưởng cout cũng là một hàm, nhưng không phải thế. C là ngôn ngữ hướng thủ tục, còn C++ là ngôn ngữ hướng đối tượng. Và cout là một đối tượng (object). Nó được định nghĩa sẵn trong C++ tương ứng với dòng xuất chuẩn (standard output stream). Stream là một khái niệm trừu tượng được hiểu như luồng dữ liệu (data flow). Standard output stream thông thường được “kết nối” (connected to) hay “chảy” (flows to) tới màn hình. Toán tử << được gọi là toán tử chèn dòng xuất (insertion output stream operator). Nó ra lệnh chuyển những nội dung của đối tượng bên tay phải sang đối tượng bên tay trái (giống như chiều mũi tên của toán tử << luôn). Ở đây endl (đối tượng này được khai báo trong namespace std như đã nói ở trên và tác dụng của nó là kết thúc một dòng, chuyển sang dòng mới) được chuyển sang bên trái cho xâu ký tự nằm trong dấu nháy kép. Sau đó toàn bộ dữ liệu này được chuyển sang cho cout, mà cout lại kết nối tới màn hình nên kết quả là trên màn hình in ra dòng text: Hello, Girl và con trỏ chuyển xuống dòng mới. Có thể mô tả bởi hình vẽ sau:

Illustration of cout's mechanism
Illustration of cout’s mechanism

Câu lệnh cuối cùng là:

return 0;

Câu lệnh này là một cách thông thường để kết thúc hàm main. Nó báo cho trình biên dịch biết là chương trình kết thúc thành công, không có lỗi.

Chương trình trên mặc dù rất đơn giản nhưng nó trình bày được cấu trúc chung của của một chương trình C++. Những bài sau mình sẽ giới thiệu những tiện ích thông dụng của C++ và cách sử dụng chúng.

Share this:

Thích bài này:

Thích

Đang tải ...