You are on page 1of 18

20 CÂU HỎI ÔN TẬP OOP

Câu 1: Nêu khái niệm về sự kế thừa và những ưu nhược điểm của kế thừa trong việc l ập
trình. Trường hợp nào thì có thể vi phạm tính kế thừa? Cho ví dụ minh họa.
- Khái niệm: Kế thừa trong lập trình là cách 1 lớp có thể thừa hưởng lại những thuộc
tính, phương thức từ 1 lớp khác và sử dụng chúng như của bản thân mình.
- Một định nghĩa trừu tượng hơn về kế thừa: là một đặc điểm của ngôn ngữ hướng đối
tượng dùng để biểu diễn mối quan hệ đặc biệt hoá – tổng quát hoá giữa các lớp.
- Lớp cơ sở thường được xử lí như 1 thành phần kiểu đối tượng của lớp dẫn xuất
Ưu điểm:
+ Cho phép xây dựng một lớp mới từ lớp đã có.
 Lớp mới gọi là lớp con(subclass) hay lớp dẫn xuất(derived class).
 Lớp đã có gọi là lớp cha(superclass) hay lớp cơ sở(base class).
+ Cho phép chia sẻ các thông tin chung nhằm tái sử dụng và đồng thời giúp ta dễ
dàng nâng cấp hay bảo trì.
+ Lớp con theo 1 tiêu chuẩn nhất định
+ cho phép tổ chức code theo 1 cách hợp lý và có cấu trúc
+cho phép tạo nên những đối tượng ở các dạng khác nhau dựa vào những lớp chúng
thừa kế
+cho phép ghi đè những phương thức ở lớp thừa kế, ta có thể thay đổi cách 1 phương
thức làm việc mà ko cần thay đổi cả code gốc
+ cho phép tạo lớp cơ sở trừu tượng để định nghĩa những hành vi cơ bản và để lại
nhưng cài đặt ứng dụng chi tiết hơn cho các lớp sau
+ Định nghĩa sự tương thích giữa các lớp, nhờ đó ta có thể chuyển kiểu tự động.
Nhược điểm:
+Khi sử dụng quá nhiều kế thừa, mã có thể trở nên khó hiểu và khó bảo trì. Kế thừa có
thể dẫn đến việc xung đột giữa các phương thức và thuộc tính.

+ Thừa kế không đúng sẽ dẫn đến giải quyết sai vấn đề


+ Một thay đổi trong lớp cha sẽ ảnh hưởng đến tất cả các lớp con.
+ Có thể thừa kế tất cả phương thức của lớp cơ sở trừ : hàm tạo,hàm hủy, toán tử gán
+ lớp dẫn xuất không thể truy nhập đến các thành phần riêng private của lớp cơ sở
+ Các chức năng được kế thừa hoạt động chậm hơn chức năng thông thường, vì nó
được thực hiện gián tiếp (lấy từ lớp cha) chứ không phải trực tiếp.
+ Thông thường, các dữ liệu thành viên trong lớp cha không được dùng. Việc này có
thể dẫn đến lãng phí bộ nhớ.
+ Nếu constructor của lớp cha có quá nhiều tham số thì lớp con khó đáp ứng được tất
cả tham số
- Trong lập trình hướng đối tượng, trường hợp có thể vi phạm tính kế thừa là khi sử
dụng quá nhiều kế thừa.
- If a subclass overrides a method in its base class but changes its behavior in a way
that is not consistent with the base class, This can lead to unexpected or incorrect
behavior in the program.
-
- Hiding a base class method or data member: If a subclass defines a method or data
member with the same name as a method or data member in its base class, it may hide
the base class member.
- Adding new data members to a subclass that are not present in the base class: If a
subclass defines new data members that are not present in its base class, it may
violate the Liskov substitution principle, because a client that expects to work with
the base class may not know how to handle the new data members in the subclass.
- If a subclass takes on additional responsibilities that are not related to its base class,
This can make the subclass harder to understand and maintain.
- If a subclass modifies the behavior of its base class directly, instead of using
inheritance or composition to extend its behavior, it may violate the open-closed
principle. This can make the subclass harder to modify and maintain over time.
- Cụ thể là trong trường hợp một lớp cơ sở được đề cập nhiều hơn một lần quacác lớp
trung gian của một lớp dẫn xuất
- VD về kế thừa:
class Animal {
protected:
string name;
int age;
public:
void Xuat() {
cout << name << “,” << age << “,” ;
}
};
class Dog: public Animal {
private:
string say =”GauGau”;
public:
Dog() {name = “Dog”; age = 2;}
void Xuat() {
Animal :: Xuat();
cout << say;
}
};
Lớp con Dog kế thừa thuộc tính name và age của lớp cha là Animal. Ngoài ra, ở lớp
Dog cũng định nghĩa thuộc tính mới là say;
Ví dụ về quy phạm tính kế thừa:
Class A
{};
Class B: public A{};
Class C:public A{};
Class D: public B, public C{};
Trong ví dụ này A là cơ sở của 2 lớp cơ sở trực tiếp của D là B và C .Nói cách khác 2
lớp cơ sở A cho D
Giải pháp là khai báo A như một lớp cơ sở kiểu virtual cho cả B và C.
Class B:virtual public A {}
Class C: virtual public A{}
Câu 2: Nêu khái niệm về trừu tượng hóa và những ưu nhược điểm của trừu tượng hóa
Trừu tượng hóa – Abstraction Cách nhìn khái quát hóa về một tập các đối tượng có chung các
đặc điểm được quan tâm (và bỏ qua những chi tiết không cần thiết).
Cho ví dụ minh họa.
- Ưu điểm của tính trừu tượng trong lập trình hướng đối tượng là
- giúp giảm sự phức tạp của mã nguồn và
- tăng khả năng tái sử dụng của mã nguồn.
- giảm thiểu sự phụ thuộc giữa các thành phần của phần mềm
- tăng tính bảo mật của mã nguồn vì giảm giới hạn truy cập của người dùng đến các
thông tin bảo mật
- Nhược điểm của tính trừu tượng là
- sẽ thiếu thông tin, dữ liệu không liên quan.
- Giảm hiệu suất chạy chương trình
- Giới hạn quyền truy cập đến các chi tiết cài đặt
- Ví dụ minh họa về tính trừu tượng trong C++:
#include<iostream>
using namespace std;
class Shape{
public:
virtual void draw() = 0;
};
class Rectangle: public Shape{
public:
void draw(){
cout<<"Drawing Rectangle"<<endl;
}
};
class Circle: public Shape{
public:
void draw(){
cout<<"Drawing Circle"<<endl;
}
};
int main(){
Shape *s;
Rectangle r;
Circle c;
s = &r;
s->draw();
s = &c;
s->draw();
return 0;
}
Trong ví dụ này, ta có một lớp Shape là lớp trừu tượng với một phương thức draw() là
phương thức ảo thuần ảo (pure virtual method). Lớp Rectangle và Circle kế thừa từ lớp
Shape và cài đặt lại phương thức draw(). Trong hàm main(), ta khởi tạo một con trỏ s
kiểu Shape và gán cho nó địa chỉ của đối tượng r kiểu Rectangle. Sau đó ta gọi phương
thức draw() thông qua con trỏ s. Kết quả khi chạy chương trình sẽ là “Drawing
Rectangle” và “Drawing Circle” .
Câu 3: Nêu khái niệm về đa hình và những ưu nhược điểm của đa hình trong việc lập
trình. Cho ví dụ minh họa.
- Đa hình (polymorphism) là một trong bốn tính chất của lập trình hướng đối tượng. Nó
cho phép các đối tượng có thể có những hành vi khác nhau để phù hợp với tình huống
đó. đa hình luôn đi kèm với kế thừa.
- Ưu điểm của đa hình trong lập trình là giúp cho việc lập trình trở nên linh hoạt và dễ
dàng hơn. Điều này giúp cho việc mở rộng và bảo trì mã nguồn trở nên dễ dàng hơn.
- Tuy nhiên, đa hình cũng có nhược điểm là khi sử dụng quá nhiều, nó có thể làm cho
mã nguồn trở nên khó hiểu và khó bảo trì.
- VD:
class Animal {
public:
virtual void sound() { cout << "Animal sound" <<endl;}
};
class Dog: public Animal {
public:
void sound() { cout << "Dog sound" <<endl; }
};
class Cat: public Animal {
public:
void sound() { cout << "Cat sound" <<endl; }
};
Trong ví dụ này, ta có 3 class là Animal, Dog và Cat. Class Dog và Cat kế thừa từ
class Animal. Class Animal có một phương thức ảo là sound(). Class Dog và Cat
override lại phương thức này để phù hợp với tính chất của chúng. Khi gọi phương
thức sound(), ta sẽ được kết quả tương ứng với loại đối tượng mà con trỏ đang trỏ tới.
Vi phạm tính đa hình :
Là lời gọi phương thức bắt nguồn từ đối tượng của lớp nào thì phương thức của lớp
đó sẽ được thực hiện
Nhưng nếu lớp gọi xuất phát từ một con trỏ của kiểu lớp nào thì phương thức của lớp
đó sẽ được thực hiện . bất kể con trỏ chứa địa chỉ của đối tượng nào
Giải pháp là biến phương thức đó thành phương thức ảo
Câu 4: Nêu khái niệm về đóng gói và những ưu nhược điểm của đóng gói trong việc
lập trình. Trường hợp nào thì có thể vi phạm tính đóng gói? Cho ví dụ minh họa.
- Đóng gói: Nhóm những gì có liên quan với nhau vào làm một để sau này có thể dung
một cái tên để gọi đến. Tính đóng gói “đóng gói” thuộc tính và phương thức của đối
tượng(hoặc lớp) thông qua việc giới hạn quyền truy cập(hoặc thay đổi) giá trị của
thuộc tính hoặc quyền gọi phương thức. Nói cách khác tính đóng gói cho phép kiểm
tra quyền truy cập(và thay đổi) giá trị của thuộc tính hoặc quyền gọi phương thức của
đối tượng(hoặc lớp) và đối tượng(hoặc lớp) con
- Ưu điểm của tính đóng gói trong OOP là giúp che giấu thông tin và bảo vệ dữ liệu
của lớp khỏi sự truy cập từ bên ngoài. Điều này giúp cho việc phát triển phần mềm
được dễ dàng hơn, giảm thiểu sự phụ thuộc giữa các thành phần của phần mềm và
tăng tính tái sử dụng của mã nguồn.
- Nhược điểm của tính đóng gói là khi muốn truy cập vào các thành viên private của
lớp thì ta phải sử dụng các phương thức public được cung cấp bởi lớp đó. Nếu không
có các phương thức public này thì ta không thể truy cập được vào các thành viên
private của lớp.
- Trường hợp vi phạm tính đóng gói:
+ khi lớp con viết đè hay truy cập đến các thành phần protected của lớp cha, nó có thể
dẫn đến những thay đổi không ngờ được => dẫn đến lỗi

- khi khai báo lớp con là bạn của lớp cha.


- VD:
class Nguoi {
friend class SinhVien;
char* HoTen;
int NamSinh;
public:
//…..
};
class SinhVien : public Nguoi {
char* MaSo;
public:
// …
void Xuat() const {
cout << “Sinh vien, ma so: “ << MaSo << “,ho ten: “ << HoTen;
}
};
Khai báo lớp bạn như trên, lớp SinhVien có thể truy xuất các thành phần private của
lớp Nguoi.
Câu 5:
a. Phân biệt các phạm vi truy cập private, protected và public.
- Private: mọi thành phần được khai báo trong private chỉ được truy xuất bên trong
phạm vi lớp và hàm bạn, lớp bạn.
- Public: mọi thành phần được khai báo trong public đều được truy xuất ở bất kỳ hàm
nào.
- Protected: mọi thành phần được khai báo trong protected chỉ được truy xuất bên trong
phạm vi lớp và có thể truy cập từ lớp dẫn xuất, hàm bạn, lớp bạn.
b. Cho biết ý nghĩa và mục đích của các hàm get/set trong một lớp .
- Hàm set: Vì dữ liệu được khai báo trong nhãn private ch ỉ được truy xu ất trong
phạm vi lớp đó, nếu muốn thay đổi dữ liệu đó ở ngoài phạm vi lớp thì phải
dùng hàm set, ngoài ra còn để kiểm soát thông tin nhập vào biến đó có phù hợp
với đề bài hay không.
- Hàm get: Tương tự như set, muốn lấy dữ liệu được khai báo trong nhãn private
thì chỉ được truy xuất trong phạm vi lớp, nên nếu muốn truy xuất dữ liệu đó ở
ngoài phạm vi lớp phải dùng hàm get để lấy dữ liệu ra.
Câu 6:
a. Phân biệt khái niệm lớp và đối tượng trong lập trình hướng đối tượng.
- Lớp là 1 mô hình trừu tượng của nhóm các đối tượng cùng bản chất, ngược lại mỗi đối
tượng là một thể hiện cụ thể cho những trừu tượng đó.
- Lớp là cái ta thiết kế và lập trình còn đối tượng là cái ta tạo ra(từ 1 lớp) tại thời gian
chạy.

Lớp Đối tượng


Là một template chung cho tất cả các đối tượng, là một mô Là một thể hiện của lớp
tả trừu tượng
Chỉ được khai báo một lần Có thể có nhiều đối tượng thuộc
lớp
Khi khai báo thì không được cấp phát vùng nhớ Khi khai báo thì được cấp phát
vùng nhớ
Là một nhóm đối tượng giống nhau Là những đối tượng cụ thể có thật

b. Trình bày khái niệm đa hình trong lập trình hướng đối tượng. Cho ví dụ minh họa
- Tính đa hình là hiện tượng các đối tượng thuộc các lớp khác nhau có thể hiểu cùng
một thông điệp theo các cách khác nhau.
- Ví dụ: có 3 con vật: chó, mèo, lợn. Khi ta bảo “kêu” thì con chó sẽ kêu gâu gâu, con
mèo sẽ kêu meo meo và con heo sẽ kêu ẹt ẹt. Cả 3 con vật có thể hiểu cùng một thông
điệp là “kêu” nhưng thực hiện theo các cách khác nhau.
Câu 7: Phân biệt các kiểu kế thừa private, protected, public.
Phạm vi truy từ khoá dẫn Private Protected Public
cập xuất
Private X X X
Protected Private Protected Protected
Public Private Protected Public
- Thành phần private ở lớp cha thì không truy xuất được ở lớp con.
- Kế thừa public: Lớp con kế thừa public từ lớp cha thì các thành phân protected của lớp cha trở
thành protected của lớp con, các thành public của lớp cha trở thành public của lớp con.
- Kế thừa protected: Lớp con kế thừa protected từ lớp cha thì các thành phần protected và public
của lớp cha trở thành protected của lớp con.
- Kế thừa private: Lớp con kế thừa private từ lớp cha thì các thành phần protected và public của
lớp cha thành private của lớp con.
Câu 8: Trình bày các đặc điểm quan trọng của lập trình hướng đối tượng.
• Trừu tượng hóa – Abstraction: Trừu tượng là quá trình tạo ra các lớp trừu tượng để mô
hình hóa các đối tượng trong thế giới thực. Nó giúp tập trung vào các khía cạnh quan
trọng và ẩn đi các chi tiết không cần thiết.
• Đóng gói – Encapsulation: Đóng gói là quá trình kết hợp dữ liệu và các phương thức hoạt
động trên dữ liệu thành một đơn vị độc lập. Điều này giúp bảo vệ dữ liệu và ẩn thông tin
chi tiết về cách hoạt động bên trong của đối tượng.
• Thừa kế - Inheritance: Kế thừa cho phép lớp con kế thừa các thuộc tính và phương thức
từ lớp cha. Điều này giúp tái sử dụng mã nguồn và xây dựng các mối quan hệ phân cấp
giữa các lớp.
• Đa hình – Polymorphism: Đa hình cho phép sử dụng các phương thức cùng tên nhưng
với cách thức thực hiện khác nhau trong các lớp khác nhau. Điều này cho phép gọi cùng
một phương thức và có kết quả khác nhau tuỳ thuộc vào đối tượng gọi phương thức đó.

Câu 9: Trình bày khái niệm của lớp cơ sở trừu tượng (abstract class). Lớp cơ sở trừu tượng được
cài đặt trong C++ như thế nào?
- Lớp cơ sở trừu tượng(Abstract Class) là lớp có ít nhất một phương thức thuần
ảo(pure virtual), hàm thuần ảo được xác định là một hàm virtual có kết thúc khai báo
hàm là “=0”. VD: virtual voi Nhap() = 0;
- Trong trường hợp lớp cơ sở trừu tượng có tất cả các phương thức là thuần ảo thì được
gọi là interface( giao diện).
- VD cài đặt:
Class Vehicle {
private:
string id;
double price;
public:
virtual void Input() = 0;
virtual void Output() = 0;
};
Câu 10:
a. Hàm thuần ảo là gì? Lớp trừu tượng là gì? Cho ví dụ minh họa.
- Hàm thuần ảo( Phương thức ảo thuần tuý) có ý nghĩa cho việc tổ chức sơ đồ phân
cấp các lớp, nó đóng vai trò chừa sẵn chỗ trống cho các lớp con điền vào với phiên
bản phù hợp. Phương thức ảo thuần tuý là phương thức ảo không có nội dung, được
khai báo với từ kháo virtual và được gán giá trị = 0.
- Khi lớp có phương thức ảo thuần tuý, lớp trở thành lớp cơ sở trừu tượng. Lớp cơ sở
trừu tượng không có đối tượng nào thuộc về chính nó.
- VD:
class Shape{ //Abstract
public:
virtual void Draw() = 0; //pure virtual function
}
Trong ví dụ trên, các hàm thành phần trong lớp Shape là phương thức ảo thuần tuý và
lớp Shape là lớp cơ sở trừu tượng. Nó bảo đảm không thể tạo được đối tượng thuộc
lớp Shape.
b. Hãy nêu các đặc điểm quan trọng của lập trình hướng đối tượng. (trùng câu 8)
Câu 11: Phân biệt khái niệm overload (tải chồng) và override (ghi đè) trong lập trình hướng đối
tượng.
Override Overload
Khái Là 1 tính năng cho phép một hoặc nhiều Nạp chồng phương thức là có vài
niệm lớp con cung cấp một triển khai cụ thể phương thức trùng tên nhưng khác
của 1 phương thức đã được cung cấp nhau về đối số. Cài chồng phương
bởi lớp cha của nó. Nói cách khác, nếu thức cho phép ta tạo nhiều phiên bản
lớp con cung cấp trình triển khai cụ thể của 1 phương thức, mỗi phiên bản
của phương thức mà đã được cung cấp chấp nhận một danh sách đối số khác
bởi 1 trong các lớp cha của nó thì gọi là nhau, nhằm tạo thuận lợi cho việc
ghi đè phương thức gọi phương thức.
Hành Thay đổi hành vi hiện tại của phương Thêm hoặc mở rộng cho hành vi của
vi thức phương thức
Đa Thể hiện tính đa hình tại run time Thể hiện tính đa hình tại compile
hình
Danh Danh sách tham số phải giống nhau Danh sách tham số khác nhau(số
sách lượng, thứ tự, kiểu dữ liệu)
tham
số
Giá trị Kiểu trả về bắt buộc phải giống nhau Kiểu trả về có thể khác nhau
trả về
Phạm Xảy ra giữa 2 class có quan hệ kế thừa Xảy ra trong phạm vi cùng 1 class
vi
Câu 12: Trình bày khái niệm Hàm bạn, lớp bạn. Ưu nhược điểm. Cho ví dụ minh họa.
- Hàm bạn là hàm tự do, không thuộc lớp. Tuy nhiên hàm bạn trong có quyền truy cập
các thành viên private của lớp. Một lớp có thể có nhiều hàm bạn, và chúng phải nằm
bên ngoài class.
- Lớp bạn là một lớp được khai báo bên ngoài lớp khác nhưng được cấp quyền truy cập
vào các thành viên private và protected của lớp đó. Lớp bạn có thể được khai báo bên
trong một lớp khác hoặc bên ngoài lớp đó.
- Ưu điểm của hàm bạn và lớp bạn là giúp tăng tính đóng gói và bảo mật của dữ liệu
trong lập trình hướng đối tượng. Tuy nhiên, việc sử dụng quá nhiều hàm bạn và lớp
bạn có thể dẫn đến việc giảm tính kế thừa và đa hình của chương trình.
- VD:
class MyClass {
private:
int x = 10;
public:
friend void myFriendFunction(MyClass obj);
friend class MyFriendClass;
};

void myFriendFunction(MyClass obj) {


cout << "x is: " << obj.x << endl;
}

class MyFriendClass {
public:
void showPrivate(MyClass obj) {
cout << "x is: " << obj.x << endl;
}
}
Trong ví dụ trên, myFriendFunction() được khai báo là một hàm bạn của lớp
MyClass. MyFriendClass được khai báo là một lớp bạn của lớp MyClass.
Câu 13: Nêu vai trò của hàm tạo (Constructor), hàm hủy (destructor) trong định nghĩa lớp.
- 3 constructor: constructor có tham số, default constructor, hàm tạo sao chép.
- Constructor là hàm dùng để khởi tạo giá trị cho đối tượng, đáp ứng tính sẵn sàng.
Được khai báo như một phương thức, tên phương thức trùng với tên lớp nhưng không
có kiểu dữ liệu trả về. Một class có thể có nhiều constructor. Constructor phải có
thuộc tính public.
- Destructor là hàm dùng để hủy đối tượng khi hết phạm vi sử dụng. Được khai báo
như một phương thức, tên phương thức trùng với tên lớp và có dấu ~ ở trước. Không
có kiểu dữ liệu trả về. Destructor phải được khai báo ở nhãn public và chỉ có duy nhất
1 destructor trong class.
Câu 14: Trình bày phép gán trong lập trình hướng đối tượng. Tại sao phải xây dựng phép gán
cho lớp? Cho ví dụ minh họa.
+ toán tử gán không tạo ra đối tượng mới ,chỉ thực hiện phép gán giữa 2 đối tượng đã tồn tại
+ trong đa số các trường hợp khi lớp không có thành phần con trỏ hay tham chiếu thì toán tử gán
mặc định là đủ dùng và không cần định nghĩa một phương thức toán tử gán cho lớp
- Phép gán trong lập trình hướng đối tượng là một phép toán dùng để gán giá trị của
một đối tượng cho một đối tượng khác. Phép gán được xây dựng bằng cách sử dụng
toán tử =. Khi sử dụng phép gán, giá trị của đối tượng bên phải được gán cho đối
tượng bên trái.
- Việc xây dựng phép gán cho lớp là cần thiết vì khi sử dụng một con trỏ đối tượng
thuộc
lớp cơ sở, chúng ta không biết chắc được đối tượng mà con trỏ đó sẽ giữ có kiểu dữ
liệu gì nó có thể là một đối tượng thuộc lớp cơ sở hoặc lớp dẫn xuất.
- VD:
#include <iostream>
using namespace std;

class MyClass {
public:
int x;
MyClass(int a) { x = a; }
MyClass operator = (MyClass obj) {
x = obj.x;
return *this;
}
};

int main() {
MyClass obj1(10), obj2(20);
cout << "Before assignment: " << endl;
cout << "obj1.x = " << obj1.x << endl;
cout << "obj2.x = " << obj2.x << endl;

obj1 = obj2;

cout << "After assignment: " << endl;


cout << "obj1.x = " << obj1.x << endl;
cout << "obj2.x = " << obj2.x << endl;

return 0;
}
Trong ví dụ này, chúng ta đã xây dựng phép gán cho lớp MyClass. Phép gán này
được thực hiện bằng cách sử dụng toán tử =. Khi thực hiện phép gán obj1 = obj2, giá
trị của obj2 được sao chép vào obj1.
Câu 15: Trình bày kỹ thuật nạp chồng (overloading) trong các tình huống không lập trình hướng
đối tượng, trong lập trình hướng đối tượng và hàm bạn. Cho ví dụ minh họa?
- Nạp chồng (overloading) là một kỹ thuật trong lập trình cho phép bạn định nghĩa
nhiều hàm hoặc toán tử có cùng tên nhưng khác nhau về số lượng tham số hoặc kiểu
dữ liệu của các tham số.
- Ví dụ, trong lập trình hướng đối tượng, bạn có thể nạp chồng phương thức để cho
phép một lớp có nhiều phương thức cùng tên nhưng khác nhau về số lượng tham số
hoặc kiểu dữ liệu của các tham số.
- Trong lập trình không hướng đối tượng, bạn có thể sử dụng nạp chồng hàm để định
nghĩa nhiều hàm có cùng tên nhưng khác nhau về số lượng tham số hoặc kiểu dữ liệu
của các tham số.
- Trong hàm bạn, bạn có thể sử dụng nạp chồng hàm để định nghĩa nhiều hàm có cùng
tên nhưng khác nhau về số lượng tham số hoặc kiểu dữ liệu của các tham số.
- VD:
#include <iostream>
using namespace std;
int add(int x, int y) {
return x + y;
}
double add(double x, double y) {
return x + y;
}
int main() {
int a = 1, b = 2;
double c = 1.5, d = 2.5;
cout << add(a, b) << endl; // Output: 3
cout << add(c, d) << endl; // Output: 4
return 0;
}
Trong ví dụ này, chúng ta đã định nghĩa hai hàm add() với hai kiểu dữ liệu khác nhau:
int và double. Khi gọi hàm add() với các giá trị tương ứng, chương trình sẽ gọi hàm
add() tương ứng với kiểu dữ liệu của các giá trị được truyền vào.
Câu 16: Trình bày kỹ thuật đa năng hóa toán tử (nạp chồng toán tử) trong xây dựng một lớp. So
sánh với cách xây dựng hàm tính toán tương ứng với toán tử. Cho ví dụ minh họa.
- Nạp chồng toán tử (operator overloading) là một kỹ thuật trong lập trình hướng đối
tượng cho phép ta định nghĩa lại các toán tử có sẵn trong ngôn ngữ lập trình để thực
hiện các phép tính trên các đối tượng của lớp mà ta định nghĩa. Kỹ thuật này cho
phép ta sử dụng các toán tử như +, -, *, /, %,… để thực hiện các phép tính trên các đối
tượng của lớp mà ta định nghĩa.
- Cách xây dựng hàm tính toán tương ứng với toán tử là một cách khác để thực hiện
việc này. Tuy nhiên, việc sử dụng nạp chồng toán tử sẽ giúp cho mã nguồn của chúng
ta trở nên ngắn gọn và dễ đọc hơn.
- VD:
#include <iostream>
using namespace std;
class PhanSo {
private:
int tuSo;
int mauSo;
public:
PhanSo(int tu = 0, int mau = 1) {
tuSo = tu;
mauSo = mau;
}
PhanSo operator+(PhanSo const &obj) {
PhanSo res;
res.tuSo = tuSo * obj.mauSo + obj.tuSo * mauSo;
res.mauSo = mauSo * obj.mauSo;
return res;
}
void display() { cout << tuSo << "/" << mauSo << endl; }
};
int main() {
PhanSo a(1, 2), b(2, 3);
PhanSo ketQua = a + b; // Tương đương với PhanSo ketQua = a.cong(b);
ketQua.display();
return 0;
}
Câu 17: Trình bày kỹ thuật liên kết động. Cho ví dụ minh họa
- Kỹ thuật liên kết động (Dynamic binding) là một trong những kỹ thuật lập trình
hướng đối tượng (OOP) cho phép chương trình quyết định phương thức nào sẽ được
gọi tại thời điểm chạy chương trình.
- Một lời gọi xuất phát từ con trỏ tới phương thức ảo không liên kết với một phương
thức cố định , mà tùy thuộc vào nội dung con trỏ. Đó là sự liên kết động và phương
thức được liên kết thay đổi mỗi khi có sự thay đổi nội dung con trỏ trong quá trình
chạy chương trình.
- Ví dụ minh họa về kỹ thuật liên kết động trong ngôn ngữ C++:
#include <iostream>
using namespace std;
class Animal {
public:
virtual void sound() {
cout << "Animal sound" << endl;
}
};
class Dog : public Animal {
public:
void sound() {
cout << "Woof" << endl;
}
};
class Cat : public Animal {
public:
void sound() {
cout << "Meow" << endl;
}
};
int main() {
Animal *animal;
Dog dog;
Cat cat;
animal = &dog;
animal->sound();
animal = &cat;
animal->sound();
return 0;
}
Trong ví dụ trên, ta có 3 lớp: Animal, Dog và Cat. Lớp Animal là lớp cha của lớp Dog
và lớp Cat. Lớp cha này có một phương thức ảo (virtual method) là sound(). Lớp con
Dog và Cat đều override lại phương thức này.
Trong hàm main(), ta khai báo một con trỏ kiểu Animal và khởi tạo nó bằng một đối
tượng kiểu Dog. Sau đó, ta gọi phương thức sound() thông qua con trỏ này. Khi chạy
chương trình, phương thức sound() của lớp Dog sẽ được gọi.
Tiếp theo, ta khởi tạo con trỏ kiểu Animal bằng một đối tượng kiểu Cat và gọi
phương thức sound(). Lần này, phương thức sound() của lớp Cat sẽ được gọi.
Câu 18: Trình bày toán tử (). Cho ví dụ minh họa.
- Toán tử () trong C++ được gọi là toán tử hàm. Nó cho phép định nghĩa một hàm để
thực hiện một phép tính như một toán tử.
- Ví dụ:
#include <iostream>
using namespace std;
class Box {
protected:
double length;
public:
void setLength(double len) { length = len; }
double getLength() {return length;}
Box operator() (double len) {
Box box;
box.length = len;
return box;
}
};
int main() {
Box Box1;
Box Box2;
Box1.setLength(6.0);
Box2.setLength(8.0);
cout << "Volume of Box1 : " << Box1.getLength() <<endl;
cout << "Volume of Box2 : " << Box2.getLength() <<endl;
return 0;
}
Trong ví dụ trên, lớp Box có một toán tử hàm được định nghĩa bằng cách sử dụng từ
khóa operator() để tạo ra một hộp mới với các kích thước được chỉ định.
Câu 19: Trình bày con trỏ hàm. Cho ví dụ minh họa.
- Con trỏ hàm trong C++ là một biến lưu trữ địa chỉ của một hàm. Con trỏ hàm được
sử dụng để gán địa chỉ của hàm cho con trỏ hàm, gọi một hàm bằng con trỏ hàm,
truyền con trỏ hàm vào hàm dưới dạng đối số.
- VD:
#include <iostream>
using namespace std;
int add(int a, int b) {
return a + b;
}
int main() {
int (*p)(int, int);
p = add;
cout << p(2, 3) << endl;
return 0;
}
Trong ví dụ này, chúng ta khai báo một con trỏ hàm tên là p và có kiểu là int (*)(int, int).
Sau đó, chúng ta gán địa chỉ của hàm add cho con trỏ p. Cuối cùng, chúng ta gọi hàm add
thông qua con trỏ p.
Câu 20: So sánh hàm tạo sao chép và phép gán. Cho ví dụ minh hoạ.
- Hàm tạo sao chép được sử dụng để khởi tạo một đối tượng mới từ một đối tượng đã
có.
- Toán tử gán không tạo ra đối tượng mới, chỉ thực hiện phép gán giữa 2 đối tượng đã
tồn taị
+ Hàm tạo sao chép sẽ khởi tạo một đối tượng mới và cấp phát bộ nhớ mới cho nó,
trong khi phép gán sẽ sao chép giá trị của các thành viên từ đối tượng nguồn sang đối
tượng đích.
Nếu đã xây dựng toán tử gán mà lại dùng hàm tạo sao chép mặc định thì lại chưa đủ .
Vì việc khởi gán trong câu lệnh khởi báo sẽ không gọi tới toán tử gán mà lại gọi tới
hàm tạo sao chép
Câu lệnh new(chứa dấu bằng sẽ gọi đến hàm tạo)

+ Hàm tạo sao chép không thể được gọi trực tiếp, trong khi phép gán có thể được gọi
trực tiếp.
+ Ví dụ minh họa về hàm tạo sao chép và phép gán trong lập trình C++:
#include <iostream>
using namespace std;
class MyClass {
public:
int x;
MyClass() { cout << "Constructor called." << endl; }
MyClass(const MyClass& obj) {
x = obj.x;
cout << "Copy constructor called." << endl;
}
MyClass& operator=(const MyClass& obj) {
x = obj.x;
cout << "Assignment operator called." << endl;
return *this;
}
};
int main() {
MyClass obj1;
obj1.x = 10;
MyClass obj2 = obj1; // Copy constructor called.
cout << "obj2.x = " << obj2.x << endl;
MyClass obj3;
obj3 = obj1; // Assignment operator called.
cout << "obj3.x = " << obj3.x << endl;
return 0;
}
Trong ví dụ này, hàm tạo sao chép và phép gán của lớp MyClass được định nghĩa để
hiển thị thông báo khi chúng được gọi. Trong hàm main(), hai đối tượng obj2 và obj3
được khởi tạo từ đối tượng obj1 bằng cách sử dụng hàm tạo sao chép và phép gán.

You might also like