You are on page 1of 14

Mục lục:

Câu 1: ................................................................................................................................................... 2
Câu 2: ................................................................................................................................................... 3
Câu 3: ................................................................................................................................................... 5
Câu 4: ................................................................................................................................................... 6
Câu 5: ................................................................................................................................................... 7
Câu 6: ................................................................................................................................................... 9
Câu 7: ................................................................................................................................................... 9
Câu 8: ................................................................................................................................................. 10
Câu 9: ................................................................................................................................................. 11
Câu 10:............................................................................................................................................... 11
Câu 1:
Class (lớp) trong lập trình hướng đối tượng là một khái niệm cơ bản để mô tả các đối tượng
trong thế giới thực. Class mô tả cách mà một đối tượng được xây dựng, những thuộc tính nó
có và những hành vi mà nó có thể thực hiện.
Ví dụ, nếu chúng ta muốn mô tả một đối tượng "Sinh viên", chúng ta có thể tạo ra một lớp
"SinhVien" trong lập trình. Lớp này sẽ chứa thông tin về tên, tuổi, mã số sinh viên của một sinh
viên. Ngoài ra, lớp SinhVien cũng có thể chứa một số phương thức như tìm kiếm sinh viên theo
tên hoặc hiển thị danh sách tất cả sinh viên.
Object (đối tượng) là một phiên bản cụ thể của một lớp. Đối tượng là một thực thể duy nhất
được tạo ra từ một lớp, chứa các giá trị riêng biệt cho các thuộc tính của nó và được sử dụng
để thực hiện các hoạt động cụ thể.
Tiếp tục ví dụ về lớp "SinhVien". Chúng ta có thể tạo các đối tượng "sinh_vien_C",
"sinh_vien_B", và "sinh_vien_C" từ lớp này. Mỗi đối tượng sẽ có các thuộc tính riêng biệt như
tên, tuổi, mã số sinh viên và được sử dụng để thực hiện các hoạt động cụ thể, ví dụ như hiển
thị thông tin của một sinh viên cụ thể.
Ví dụ:
#include <iostream>
using namespace std;

class SinhVien {
public:
string ten;
int tuoi;
string mssv;

void hienThiThongTin() {
cout << "Ten: " << ten << endl;
cout << "Tuoi: " << tuoi << endl;
cout << "MSSV: " << mssv << endl;
}
};
int main() {
SinhVien sinhVienA, sinhVienB;

sinhVienA.ten = "Nguyen Van A";


sinhVienA.tuoi = 20;
sinhVienA.mssv = "SV001";

sinhVienB.ten = "Tran Thi B";


sinhVienB.tuoi = 21;
sinhVienB.mssv = "SV002";

sinhVienA.hienThiThongTin();
sinhVienB.hienThiThongTin();

return 0;
}
Câu 2: lập trình hướng đối tượng, tính trừu tượng và tính bao bọc là hai khái niệm rất quan trọng.
Tính trừu tượng (abstraction) cho phép chúng ta tập trung vào các đặc tính quan trọng của một
đối tượng mà bỏ qua các chi tiết không quan trọng. Điều này giúp mã nguồn dễ hiểu hơn và dễ
bảo trì hơn.
Tính bao bọc (encapsulation) giữ các chi tiết về đối tượng được che giấu và chỉ cho phép truy
cập thông qua các phương thức công cộng. Điều này giúp bảo mật mã nguồn và ngăn chặn
các lỗi truy cập không đúng cách.
Giả sử bạn đang thiết kế một đối tượng nhân viên. Chi tiết như họ và tên, số CMND, địa chỉ và
lương được xem là quan trọng. Trong đó, tên đối tượng là Employee. Ta có thể định nghĩa
class như sau:
class Employee {
private:
string name;
int id_number;
string address;
double salary;
public:
Employee(string name, int id_number, string address, double salary) {
this->name = name;
this->id_number = id_number;
this->address = address;
this->salary = salary;
}
string getName() {
return name;
}
int getIDNumber() {
return id_number;
}
string getAddress() {
return address;
}
double getSalary() {
return salary;
}
};

Tính kế thừa (Inheritance) trong lập trình hướng đối tượng là khả năng cho phép một lớp con
(subclass) được xây dựng dựa trên các thuộc tính và phương thức đã được xác định trong lớp
cha (superclass). Các thuộc tính và phương thức này có thể được sử dụng lại trong lớp con,
giúp tiết kiệm thời gian và giảm sự lặp lại của mã.
Ví dụ:
class Animal {
public:
void sleep() {
cout << "Zzzz..." << endl;
}
void eat() {
cout << "Nom nom nom..." << endl;
}
};

class Dog : public Animal { // Lớp Dog kế thừa từ lớp Animal


public:
void bark() {
cout << "Woof woof!" << endl;
}
};

int main() {
Dog myDog;
myDog.eat();
myDog.bark();

return 0;
}
Trong ví dụ này, lớp Dog kế thừa các phương thức sleep() và eat() từ lớp Animal. Khi đối tượng
myDog được tạo ra, nó có thể sử dụng các phương thức này cùng với phương thức bark() định
nghĩa riêng của lớp Dog.
Tính đa hình (Polymorphism) là khả năng của các đối tượng cùng loại để thực hiện các hành
động khác nhau dựa trên tính chất hoặc trạng thái riêng của chúng. Điều này có nghĩa là, khi
chúng ta gọi một phương thức trên một đối tượng, phương thức sẽ được thực thi theo cách
đặc biệt cho đối tượng đó.
Ví dụ:
class Shape {
public:
virtual void draw() {
cout << "Drawing a shape." << endl;
}
};

class Circle : public Shape {


public:
void draw() {
cout << "Drawing a circle." << endl;
}
};

class Square : public Shape {


public:
void draw() {
cout << "Drawing a square." << endl;
}
};

int main() {
Shape* myShape1 = new Circle();
Shape* myShape2 = new Square();

myShape1->draw(); // Drawing a circle.


myShape2->draw(); // Drawing a square.

return 0;
}
Trong ví dụ này, lớp Shape có một hàm ảo draw() được định nghĩa như một hàm trống. Hai lớp
con Circle và Square định nghĩa lại phương thức draw() để vẽ một hình tròn và hình vuông,
tương ứng. Trong hàm main(), hai con trỏ kiểu Shape được khởi tạo để trỏ tới các đối tượng
Circle và Square. Khi gọi phương thức draw() trên các đối tượng này thông qua con trỏ,
phương thức tương ứng với từng đối tượng được thực thi. Đây là tính đa hình trong hành động
vẽ hình của các đối tượng cùng loại Shape.

Câu 3:
Tính kế thừa (Inheritance):
• Tính kế thừa trong lập trình hướng đối tượng cho phép các lớp mới được tạo ra bằng
cách kế thừa các thuộc tính và các hành vi (method) từ các lớp đã có sẵn. Khi một lớp
được kế thừa, nó trở thành lớp cha đối với lớp mới, còn lớp mới được gọi là lớp con.
Lớp con có thể sử dụng các thuộc tính và các hành vi đã có sẵn trong lớp cha, cũng
như định nghĩa thêm các thuộc tính và các phương thức mới phù hợp với nhu cầu của
nó. Điều này giúp tiết kiệm thời gian và nguồn lực trong việc phát triển phần mềm.
Ví dụ, lớp Animal có các thuộc tính như age, weight và một phương thức makeSound(). Chúng
ta có thể tạo lớp con như Cat và Dog. Cả lớp Cat và Dog đều kế thừa các thuộc tính và
phương thức của lớp Animal. Tuy nhiên, lớp Cat có phương thức sẽ kêu Meow() và lớp Dog có
phương thức bark().
class Animal{
public:
int age, weight;
void makeSound(){
}
};

class Cat : public Animal{


public:
void Meow(){
cout<<"cat meowing"<<endl;
}
};

class Dog : public Animal{


public:
void bark(){
cout<<"dog barking"<<endl;
}
};
• Tính đa hình (Polymorphism):
Tính đa hình là tính năng của lập trình hướng đối tượng cho phép các đối tượng có thể
có nhiều hình dạng khác nhau. Trong lập trình hướng đối tượng, đa hình là việc ta định
nghĩa lại các phương thức đã có sẵn trong lớp cha trong các lớp con, nhưng với cách
cài đặt khác biệt. Với tính đa hình, chúng ta sẽ có nhiều lớp con có thể có hình dạng
hiển thị hoàn toàn khác nhau khi được gọi thông qua phương thức của lớp cha.
Ví dụ, chúng ta có lớp Shape với phương thức draw(). Sử dụng đa hình, ta có thể tạo các lớp
kế thừa Circle và Square, để tạo các hình tròn và hình vuông, nhưng khi vẽ chúng, cách vẽ của
chúng ta khác nhau. Với phương pháp đa hình, chúng ta chỉ cần gọi phương thức draw() trên
đối tượng hình dạng, và phương thức draw() được trỏ tới đối tượng đúng.
class Shape{
public:
virtual void draw(){
}
};

class Circle : public Shape{


public:
void draw(){
cout<<"draw Circle"<<endl;
}
};

class Square : public Shape{


public:
void draw(){
cout<<"draw Square"<<endl;
}
};

int main()
{
Shape *s;
Circle c;
Square sq;
s=&c;
s->draw();
s=&sq;
s->draw();
return 0;
}
Trong ví dụ này, ta khai báo lớp cha Shape với hàm ảo draw(). Lớp Circle và Square kế thừa
lớp Shape và định nghĩa lại hàm draw() theo 2 cách khác nhau. Trong hàm main, ta khởi tạo
đối tượng Circle và Square và gán con trỏ s trỏ tới đối tượng Circle, sau đó gọi phương thức
draw() thông qua con trỏ s. Kết quả khi in ra sẽ là "draw Circle". Sau đó, ta thay đổi con trỏ s để
trỏ tới đối tượng Square và gọi phương thức draw() một lần nữa. Kết quả in ra sẽ là "draw
Square". Điều này cho thấy rõ tính đa hình trong lập trình hướng đối tượng, một phương pháp
mạnh mẽ giúp cho mã nguồn gọn nhẹ và dễ bảo trì, đồng thời cung cấp tính linh hoạt trong việc
triển khai các phương thức của đối tượng.

Câu 4:
Tính đóng gói (encapsulation) trong lập trình hướng đối tượng là một khái niệm quan trọng để
giữ cho dữ liệu và các phương thức của một đối tượng được bảo vệ và không bị truy cập hoặc
thay đổi từ bên ngoài lớp. Để đạt đượcTính đóng gói (encapsulation) trong lập trình hướng đối
tượng được thể hiện bằng cách ẩn thông tin trong một lớp để người sử dụng không thể truy
xuất hoặc thay đổi các thuộc tính và phương thức của lớp đó trực tiếp. Thay vào đó, người sử
dụng chỉ có thể truy cập và thao tác với các thành phần công khai (public) mà lớp cung cấp.
Đặc điểm của tính đóng gói:
• Bảo mật: Tính đóng gói giúp bảo vệ dữ liệu và các phương thức của lớp khỏi sự xâm
nhập từ phía bên ngoài.
• Quản lý mã: Tính đóng gói giúp quản lý mã dễ dàng hơn bằng cách giữ các thành phần
của lớp tách biệt với các lớp khác.
• Dễ dàng bảo trì: Tính đóng gói giúp dễ dàng chỉnh sửa phương thức và thuộc tính của
lớp, mà không ảnh hưởng đến mã nguồn của các lớp khác.
• Giúp tái sử dụng: Khi một lớp được đóng gói tốt, các thuộc tính và phương thức của nó
có thể được sử dụng lại trong các lớp khác.
Trường hợp có thể vi phạm tính đóng gói là khi người lập trình sử dụng các thuộc tính hoặc
phương thức không công khai (private hoặc protected) của một lớp từ bên ngoài, thay vì thông
qua các phương thức công khai đã được cung cấp. Vi phạm này có thể dẫn đến lỗi hoặc làm
suy yếu tính bảo mật của chương trình.

Câu 5:
Tính kế thừa có một số ưu điểm như sau:
• Tính kế thừa giúp tăng khả năng tái sử dụng. Khi một lớp kế thừa hoặc dẫn xuất
một lớp khác, thì nó có thể truy cập tất cả các chức năng của lớp mà nó kế thừa.
• Khả năng tái sử dụng nâng cao độ tin cậy. Chúng ta chỉ cần kiểm tra và gỡ lỗi
với mã lớp cha, chứ không cần kiểm tra từng lớp con.
• Khi mã được tái sử dụng, sẽ giúp giảm chi phí phát triển và bảo trì.
• Các lớp con sẽ tuân thủ theo một giao diện (interface) chuẩn.
• Tính kế thừa giúp hạn chế sự dư thừa mã và hỗ trợ khả năng mở rộng mã.
• Lập trình viên có điều kiện thuận lợi để tạo các thư viện lớp (class libraries).
Ví dụ:
#include <iostream>
#include <string>
using namespace std;

class Vehicle {
protected:
string brand;
int year;
int mileage;

public:
Vehicle(string brand, int year, int mileage) {
this->brand = brand;
this->year = year;
this->mileage = mileage;
}

string getBrand() {
return brand;
}

int getYear() {
return year;
}

int getMileage() {
return mileage;
}

void setBrand(string brand) {


this->brand = brand;
}

void setYear(int year) {


this->year = year;
}

void setMileage(int mileage) {


this->mileage = mileage;
}
};

class Car : public Vehicle {


private:
string color;

public:
Car(string brand, int year, int mileage, string color)
: Vehicle(brand, year, mileage) {
this->color = color;
}

string getColor() {
return color;
}

void setColor(string color) {


this->color = color;
}
};

int main() {
Car myCar("Mercedes", 2020, 5000, "black");

cout << "Brand: " << myCar.getBrand() << endl;


cout << "Year: " << myCar.getYear() << endl;
cout << "Mileage: " << myCar.getMileage() << endl;
cout << "Color: " << myCar.getColor() << endl;

myCar.setBrand("BMW");
myCar.setYear(2021);
myCar.setMileage(10000);
myCar.setColor("red");
cout << "Brand: " << myCar.getBrand() << endl;
cout << "Year: " << myCar.getYear() << endl;
cout << "Mileage: " << myCar.getMileage() << endl;
cout << "Color: " << myCar.getColor() << endl;

return 0;
}
Trong ví dụ này, ta có thể thấy rõ tính kế thừa giúp giảm thiểu việc lặp lại mã và tăng tính linh
hoạt cho ứng dụng.
Câu 6:
• Overload (tải chồng) là một kỹ thuật trong OOP cho phép chúng ta định nghĩa nhiều
phương thức có cùng tên nhưng khác nhau về tham số hoặc kiểu dữ liệu đầu vào. Khi
gọi phương thức, compiler sẽ tự động phân biệt và chọn phương thức thích hợp dựa
trên số lượng tham số và kiểu dữ liệu của chúng.
• Override (ghi đè) là một kỹ thuật trong OOP cho phép một lớp con định nghĩa lại một
phương thức nằm trong lớp cha đã tồn tại. Khi lớp con ghi đè phương thức của lớp cha
thì phương thức mới này sẽ thực hiện chức năng khác với phương thức của lớp cha
ban đầu.

Câu 7:
Kế thừa là một đặc tính quan trọng trong lập trình hướng đối tượng (OOP) cho phép ta tái sử
dụng mã và cải thiện tính linh hoạt của ứng dụng. Có ba cách kế thừa chính là private,
protected và public:
• Kế thừa private: Trong kế thừa private, tất cả các thuộc tính và phương thức của lớp
cha đều trở thành private trong lớp con. Điều này có nghĩa là không có lớp con nào có
thể truy cập được đến các phương thức hay thuộc tính đó của lớp cha, trừ khi sử dụng
getter và setter để truy cập thông qua phương thức public của lớp con.
• Kế thừa protected: Trong kế thừa protected, các thuộc tính và phương thức protected
của lớp cha sẽ trở thành protected trong lớp con. Điều này có nghĩa là các phương thức
và thuộc tính này có thể được truy cập trực tiếp từ lớp con hoặc các lớp kế thừa khác
của lớp cha nhưng không thể được truy cập bên ngoài.
• Kế thừa public: Trong kế thừa public, các thuộc tính và phương thức public của lớp cha
sẽ trở thành public trong lớp con. Điều này có nghĩa là các phương thức và thuộc tính
này có thể được truy cập trực tiếp từ lớp con hoặc từ bất kỳ nơi nào bên ngoài lớp con.
Câu 8:
Hàm thuần ảo (pure virtual function) là một hàm ảo (virtual function) trong lớp cơ sở (base
class) mà không có định nghĩa được cung cấp. Các lớp kế thừa (derived class) phải định nghĩa
lại hàm này để sử dụng, nếu không sẽ bị lỗi compile time.
Để định nghĩa một hàm thuần ảo, ta sử dụng toán tử `= 0` ở cuối khai báo hàm như sau:
class Shape {
public:
virtual void draw() = 0;
};

class Circle : public Shape {


public:
void draw() {
cout << "Drawing a circle" << endl;
}
};

class Square : public Shape {


public:
void draw() {
cout << "Drawing a square" << endl;
}
};
Trong ví dụ này, lớp `Shape` có một hàm thuần ảo `draw()` được khai báo. Lớp `Circle` và
`Square` được kế thừa từ lớp `Shape` và phải định nghĩa lại hàm `draw()` để sử dụng.

Lớp trừu tượng (abstract class) là một lớp mà có chứa ít nhất một hàm thuần ảo và không thể
khởi tạo đối tượng trực tiếp từ lớp này. Lớp trừu tượng được sử dụng để định nghĩa các chỉ
dẫn / prototype cho các lớp kế thừa.
Ví dụ:
#include <iostream>
using namespace std;

class Shape{
protected:
float dimension;
public:
void getDimension(){
cin >> dimension;
}
virtual float calculateArea() = 0;
};
class Square : public Shape{
public:
float calculateArea() {
return dimension * dimension;
}
};
class Circle : public Shape{
public:
float calculateArea() {
return 3.14 * dimension * dimension;
}
};
void main(){
Square square;
Circle circle;
cout << "Enter the length of the square: ";
square.getDimension();
cout << "Area of square: " << square.calculateArea() << endl;
cout << "\nEnter radius of the circle: ";
circle.getDimension();
cout << "Area of circle: " << circle.calculateArea() << endl;
system("pause");
}
Câu 9:
Lập trình hướng đối tượng (OOP) là một phương pháp lập trình dựa trên các đối tượng và
hành động giữa chúng. Các đối tượng có thể bao gồm các đối tượng thực tế như xe hơi, nhà,
vật thể trong trò chơi, cũng như các đối tượng rời rạc như list, set. Dưới đây là một số đặc điểm
quan trọng của lập trình hướng đối tượng:
• Tính trừu tượng: Lập trình hướng đối tượng cho phép ta trừu tượng hóa các đối tượng
thực tế và biến chúng thành các đối tượng trừu tượng. Điều này giúp ta dễ dàng quản lý
các đối tượng này hơn và giảm sự phụ thuộc lẫn nhau giữa các đối tượng.
• Tính đóng gói: Tính đóng gói trong OOP cho phép ta giấu đi các chi tiết bên trong một
đối tượng và chỉ cung cấp các phương thức public để truy cập đến các thông tin của đối
tượng đó. Các phương thức public này được định nghĩa để đảm bảo tính hợp lệ dữ liệu
khi thao tác với đối tượng.
• Tính kế thừa: Tính kế thừa trong OOP cho phép các đối tượng mới được tạo ra bằng
cách kế thừa các thuộc tính và hành vi từ các đối tượng đã tồn tại. Điều này giúp đơn
giản hóa mã và giảm sự trùng lặp trong mã.
• Tính đa hình: Tính đa hình trong OOP cho phép các đối tượng có thể được xử lý bằng
các cách khác nhau tùy thuộc vào mối quan hệ giữa chúng. Điều này cho phép tạo ra
các phương thức với tên giống nhau nhưng có cách thức hoạt động khác nhau cho các
đối tượng khác nhau.
• Tính tái sử dụng: Tính tái sử dụng trong OOP cho phép ta sử dụng lại mã đã được viết
trước đó. Việc này dễ dàng hơn khi sử dụng các đối tượng và kế thừa các đối tượng
được định nghĩa sẵn.
Câu 10:
Lớp cơ sở trừu tượng (Abstract class) là một lớp không thể khởi tạo được đối tượng trực tiếp
và chứa một hoặc nhiều phương thức thuần ảo (pure virtual method). Lớp trừu tượng được sử
dụng để định nghĩa giao diện (interface) cho các lớp kế thừa (derived class). Với việc sử dụng
lớp trừu tượng, ta có thể định nghĩa các phương thức thuần ảo và để các lớp kế thừa định
nghĩa và triển khai chúng như ý muốn.
Lớp cơ sở trừu tượng không bao giờ có thể được khởi tạo trực tiếp, do đó không thể có đối
tượng của lớp trừu tượng. Tuy nhiên, ta có thể khai báo con trỏ của lớp trừu tượng để trỏ tới
các đối tượng của lớp kế thừa, và gọi các phương thức của lớp trừu tượng.
Cú pháp để khai báo một lớp trừu tượng trong C++ là sử dụng từ khóa `virtual` kết hợp với
phương thức thuần ảo bằng cách sử dụng toán tử " = 0" ở cuối khai báo phương thức

Ví dụ: #include <iostream>

class Shape {
public:
virtual void draw() = 0;
};

class Circle: public Shape {


public:
void draw() {
std::cout << "Circle::draw()\n";
}
};

int main() {
Shape* s = new Circle;
s->draw();

return 0;
}

You might also like