Class và đối tượng trong C++
Công ty Vĩnh Cửu tuyển dụng lập trình viên Java

1- Giới thiệu

Tài liệu được viết dựa trên:
  • Eclipse 4.5 Mars

2- Chú ý khi mở Eclipse

Nếu bạn làm việc với: Windows 64bit + Eclipse 64bit + Java64bit, bạn cần phải mở Eclipse với quyền Administrator, có một rắc rối là Eclipse không in các message ra màn hình Console trong trường hợp chạy ở chế độ thông thường

3- Tạo project C++ trên Eclipse

Trên Eclipse chọn:
  • File/New/Other..
Project của bạn đã được tạo ra.
Project của bạn đã được tạo ra, có sẵn một file nguồn cpp, chúng ta sẽ giải thích cấu trúc của file nguồn này sau.

4- Chạy ứng dụng C++

Trong lần đầu tiên, bạn cần phải biên dịch project của bạn. Nhấn phải vào Project chọn "Project/Build All".
Có thể trên Eclipse của bạn đang có một vài Project, để chạy Project hiện tại, bạn cần thêm mới một cấu hình chạy.
Bạn đang lập trình, bạn nên chọn chế độ chạy là DEBUG.

5- Giải thích cấu trúc chương trình C++

Ở trên bạn đã chạy một chương trình C++ đơn giản, nó in ra màn hình một chuỗi. Trong C để in ra một chuỗi bạn sử dụng printf, nhưng với C++ bạn sử dụng cout, tất nhiên tất cả các hàm của C vẫn tiếp tục được sử dụng trong C++.

Hãy xem cách sử dụng cout:
// Lệnh cout sử dụng để in ra màn hình một chuỗi:

cout << "One";


// In ra màn hình chuỗi "One " và tiếp theo là chuỗi "Two ".

cout << "One "  << "Two ";


// In ra màn hình chuỗi "One " tiếp theo là chuỗi "Two " tiếp theo là số 3.

cout << "One " << "Two "  <<  3 ;

// In ra màn hình chuỗi "One" và tiếp theo kết thúc dòng (Một ký tự xuống dòng).

cout << "One" << endl;
  • TODO

6- Class đầu tiên của bạn

C++ ra đời mục đích chính là đưa lập trình hướng đối tượng vào ngôn ngữ lập trình C. Và class chính là một khái niệm của C++. Class chính là một bản kế hoạch (blueprint) của (để tạo ra) các đối tượng.

Để đơn giản và dễ hiểu, tôi sẽ sử dụng class để mô hình hóa một hình chữ nhật với chiều dài và chiều cao, và một hàm để tính diện tích hình chữ nhật.
Tạo một file nguồn Rectangle.cpp:
Code:
Rectangle.cpp
#include <iostream>
using namespace std;

namespace mynamespace {

   class Rectangle {

       private:
           int width;
           int height;

       public:
           Rectangle();
           Rectangle(int, int);

       public:
           int getArea() {
               return  width * height ;
           }
           int getWidth() {
               return width;
           }
           int getHeight()  {
               return height;
           }
   };

   Rectangle::Rectangle() {
       width = 10;
       height = 5;
   }

   Rectangle::Rectangle(int a, int b) {
       width = a;
       height = b;
   }
}


// Khai báo sử dụng các thư viện nằm trong không gian tên 'mynamespace'.
// Nghĩa là bao gồm cả class Rectangle (Vì nó nằm trong không gian tên này).
using namespace mynamespace;

int main() {

 // Tạo một hình chữ nhật 'rect1' theo phương thức khởi tạo 2 tham số Rectangle(int, int).
 // Giá trị 5 được gán vào cho width, giá trị 4 được gán vào cho height.
 Rectangle rect1(5, 4);

 // Tạo một hình chữ nhật 'rect2' theo phương thức khởi tạo mặc định Rectangle()
 // width, height của nó là mặc định
 Rectangle rect2;

 cout << "rect1:" << endl;
 // Gọi phương thức lấy ra chiều rộng (width).
 cout << " width: " << rect1.getWidth() << endl;
 // Gọi phương thức lấy ra chiều cao (height).
 cout << " height: " << rect1.getHeight() << endl;
 // Gọi phương thức tính diện tích.
 cout << " area: " << rect1.getArea() << endl;

 cout << "rect2:" << endl;
 cout << " width: " << rect2.getWidth() << endl;
 cout << " height: " << rect2.getHeight() << endl;
 cout << " area: " << rect2.getArea() << endl;
 return 0;
}
Chú ý: Chương trình C/C++ chỉ cho phép một hàm main() trong toàn bộ project, vì vậy bạn cần đổi tên các hàm main() khác thành main_xxx() trước khi chạy ví dụ này.
Chạy ví dụ:
Chú ý: Có một số từ khóa private, protected, public có thể được đặt trước trường (field), phương thức (method) hoặc phương thức khởi tạo (constructor). Tạm thời chúng ta không nói về chúng, đó là cái access modifier (độ truy cập) sẽ được tôi đề cập trong bài hướng dẫn tiếp theo:
  • TODO: LINK?
Bây giờ bạn cần xem các giải thích về Class, nó vô cùng quan trọng.

7- Ví dụ C++ Class (2)

Chúng ta xem tiếp một ví dụ C++ Class, mà khai báo phương thức khởi tạo (Constructor) và các phương thức (method) nằm hết trong class.
Circle.cpp
#include <iostream>
#include <math.h>
using namespace std;


namespace mynamespace {

   class Circle {

       private:
           int radius;

       public:
           Circle() {
               radius = 100;
           }
           // Phương thức khởi tạo (Constructor) một tham số.
           // Gán giá trị trong tham số cho trường radius.
           Circle(int r) {
               radius = r;
           }

       public:
           float getArea() {
               // M_PI là hằng số định nghĩa trong <math.h>
               return  M_PI * radius* radius ;
           }
           // Phương thức trả về bán kính đường tròn.
           // (Nội dung của phương thức này được viết tại nơi khác).
           int getRadius();

           // Phương thức sét lại giá trị cho bán kính.
           void setRadius(int r){
               radius = r;
           }
   };

   // Nội dung phương thức getRadius() của class Circle.
   int Circle::getRadius() {
        return radius;
   }
}

// Khai báo sử dụng không gian tên 'mynamespace'.
// (Class Circle nằm trong không gian tên này).
using namespace mynamespace;

int main() {

   // Tạo một đường tròn bán kính 5.
   Circle circle1(5);

   // Tạo một đường tròn bán kính mặc định (100).
   Circle circle2;

   cout << "Circle 1:" << endl;
   cout << " radius: " << circle1.getRadius()  << endl;
   cout << " area: " << circle1.getArea() << endl;

   cout << "Circle 2:" << endl;
   cout << " radius: " << circle2.getRadius() << endl;
   cout << " area: " << circle2.getArea() << endl;

   // Gọi phương thức sét giá trị mới cho bán kính đường tròn 2.
   circle2.setRadius(200);

   cout << "Circle 2 (After set new Radius):" << endl;
   cout << " radius: " << circle2.getRadius() << endl;
   cout << " area: " << circle2.getArea() << endl;

   return 0;
}
Chạy ví dụ:

8- Class trong C++ (3)

Khi bạn tạo một class bằng Wizard của Eclipse nó sẽ tạo ra 2 file ClassName.hClassName.cpp. Trong đó ClassName.h khai báo rằng class của bạn bao gồm các trường (field), phương thức (method) và các phương thức khởi tạo nào. Còn nội dung của chúng sẽ được viết trong ClassName.cpp.

Hãy xem một ví dụ, bạn tao ra class Person trên Eclipse với sự trợ giúp của Wizard.
Tạo một class có tên Person và nằm trong namespace (Không gian tên) mynamespace.
Class Person đã được tạo ra, nó có 2 file Person.cpp & Person.h
Bây giờ bạn cần sửa code của Person.h & Person.cpp:
Person.h
#ifndef PERSON_H_
#define PERSON_H_

// Khai báo <string> để sử dụng class string.
#include <string>

// Khai báo 'using namespace std' để sử dụng string,cout,..
using namespace std;

namespace mynamespace {

    // Class Person mô phỏng một lớp người.
    class Person {

        private:
            // Trường name (tên người).
            string name;

        public:
            // Phương thức khởi tạo mặc định
            Person();
            // Phương thức khởi tạo với 1 tham số.
            Person(string);

            // Phương thức hủy đối tượng (Destructor)
            virtual ~Person();



        public:
            // Phương thức trả về tên người.
            string getName();
            // Phương thức sét đặt tên người.
            void setName(string);

    };

}

#endif
Person.cpp
// Khai báo nhúng thêm file Person.h vào.
#include "Person.h"
#include <iostream>
#include <string>

using namespace std;

namespace mynamespace {

    Person::Person() {
        // Gán tên mặc định là Anonymous (nặc danh).
        name = "Anonymous";
    }

    Person::Person(string name) {
        // Gán giá trị cho trường name của Person.
        // Sử dụng this -> name ám chỉ trường name của Person
        // (Để tránh nhầm lẫn với name trong tham số).
        this-> name = name;
    }

    // Phương thức hủy đối tượng luôn có cùng tên với Class và có ~ phía trước.
    // Phương thức hủy luôn luôn không có tham số.
    Person::~Person() {
        cout<< "Destructor called" <<endl ;
    }


    // Nội dung của phương thức getName() của class Person.
    string Person::getName()  {
        return this-> name;
    }

    // Sét đặt tên mới.
    void Person::setName(string newName)  {
        // Gán giá trị mới vào cho trường name của Person.
        name = newName;
    }

}

Destructor (Phương thức hủy đối tượng):

Các đối tượng khi được tạo ra, và không còn được sử dụng nữa chúng sẽ được loại bỏ khỏi bộ nhớ máy tính, ngay trước khi nó bị loại bỏ khỏi bộ nhớ phương thức hủy (Destructor) sẽ được gọi. Thông thường khi bạn tạo ra một đối tượng và có sử dụng các tài nguyên khác trong hệ thống chẳng hạn mở file để đọc bạn có thể giải phóng file trong hàm hủy của đối tượng.
Bạn có thể sử dụng class Person trên một file nguồn khác.
PersonTest.cpp
#include <iostream>
using namespace std;

// Khai báo sử dụng namespace 'mynamespace'.
using namespace mynamespace;

int main() {

   // Tạo một đối tượng Person
   Person billGate("Bill Gate");

   cout << "billGate.getName(): " << billGate.getName() << endl;

   // Tạo một đối tượng Person theo phương thức khởi tạo mặc định.

   Person aPerson;

   cout << "aPerson.getName(): "<< aPerson.getName() << endl;

   cout << "aPerson set new name" << endl;

   // Sét name mới cho aPerson
   aPerson.setName("Markus Hess");

   cout << "aPerson.getName(): "<< aPerson.getName() << endl;

   return 0;
}
Chạy ví dụ: