So sánh overload và override trong c

In C++, any method in a derived class only overrides the method in the base class if their declarations match (I say "match" but I don't know the formal term for that). That is, all arguments must have the same type, and const qualification of this must be the same. If anything there mismatches, the method in the derived class hides all methods with the same name, instead of overriding. This is what the "ERROR" in your picture tries to tell you. So // overrides in a comment in that picture is incorrect and misleading.

Yes, many C++ teachers actually don't understand these somewhat obscure details.

BTW additionally, if you want to override, the method in your base class should be virtual; otherwise, polymorphism won't work. If it was not virtual, we also say that the derived-class method hides the base-class method. Here, however, the part about hiding has almost no meaning; what this term really wants to express is that you're not overriding.

In addition, overloading is, as you noticed, presence of several methods with the same name but different signatures. They should all be present in the derived class to be useful - if the derived class has only one method fa1, and the other fa1 are in the base, they will be hidden. However, there is syntax sugar which "copies" all fa1 from base to derived, disabling all that hiding semantics:

class A
{
public:
    void fa1();
    void fa1(int);
};
class B: public A
{
public:
    using A::fa1;
    void fa1(int, int);
};
...
B b;
b.fa1(); // calls A::fa1()
b.fa1(4); // calls A::fa1(int)
b.fa1(4, 8); // calls B::fa1(int, int)


The part about hiding is rarely, if ever, useful. When overriding, you should tell this to your compiler - use the

class A
{
public:
    virtual void fa1(int) {}
    void fa2(int) {}
};
class B: public A
{
public:
    void fa1(int) override {} // OK
    void fa1() override {} // ERROR: doesn't really override - different signature
    void fa2(int) override {} // ERROR: doesn't really override - not virtual in base
};

0 keyword for that. The compiler will then check that your code works as you intended.

Ở phần 1,VietnamWorks inTECH đã giới thiệu đến các bạn những câu hỏi cơ bản về OOP thường gặp khi phỏng vấn. Trong phần 2 này, bài viết sẽ tiếp tục mang đến 15 câu hỏi nâng cao khác, nào cùng theo dõi nhé!

16. Sự khác biệt giữa overloading và overriding là gì?

Tính năng đa hình thời gian biên dịch (compile-time polymorphism) được gọi là overloading (quá tải) khi một thực thể có nhiều triển khai cùng tên. Nạp chồng hàm (overloading method) và nạp chồng toán tử (operator overloading) là hai ví dụ.

Overriding là một dạng đa hình thời gian chạy trong đó một thực thể (entity) có cùng tên nhưng được triển khai theo một cách khác. Phương thức này được thực hiện với sự trợ giúp của các chức năng ảo.

17. Tính kế thừa (Inheritance) có hạn chế nào không?

Có. Mặc dù tính kế thừa là một tính năng rất mạnh của OOP, tuy nhiên nó vẫn còn một vài nhược điểm:

  • Để thực hiện được tính năng cần phải đi qua một số lớp, nên việc kế thừa sẽ mất nhiều thời gian hơn để xử lý.
  • Lớp cơ sở và lớp con đều tham gia vào quá trình kế thừa, đồng thời có quan hệ chặt chẽ với nhau. Do đó, nếu cần thay đổi, có thể cần phải được thực hiện ở cả hai lớp cùng một lúc.
  • Việc thực hiện kế thừa cũng khá khó khăn. Do đó, nếu không được triển khai đúng cách, điều này có thể dẫn đến những lỗi không lường trước được hoặc kết quả đầu ra không chính xác.

18. Có những loại kế thừa nào?

Kế thừa có thể được phân thành 5 loại như sau:

  • Đơn kế thừa (Single Inheritance): Class con kế thừa trực tiếp từ class cơ sở.
  • Đa kế thừa (Multiple Inheritance): Class con bắt nguồn từ nhiều class cơ sở.
  • Kế thừa đa cấp (Multilevel Inheritance): Class con kế thừa từ class cha, class cha này cũng được kế thừa từ ​​một lớp cơ sở khác.
  • Kế thừa phân cấp (Hierarchical Inheritance): Nhiều class con bắt nguồn từ một class cơ sở duy nhất.
  • Kế thừa lai (Hybrid Inheritance): Kế thừa bao gồm nhiều kiểu thừa kế đã chỉ định ở trên.

19. Interface là gì?

Interface (giao diện hay lớp giao diện) là một class duy nhất chứa nhiều phương thức mà không bao gồm định nghĩa. Bên trong một giao diện, chỉ cho phép khai báo phương thức và cũng không thể tạo đối tượng bằng interface.

20. Lớp trừu tượng (Abstract class) khác với giao diện (Interface) như thế nào?

Lớp trừu tượng

Giao diện

khi một lớp trừu tượng được kế thừa, lớp con không bắt buộc phải cung cấp định nghĩa của phương thức trừu chỉ khi lớp con thực sự sử dụng nó.

Khi một giao diện được triển khai, lớp con được yêu cầu chỉ định tất cả các phương thức của giao diện cũng như việc triển khai chúng.

Một lớp trừu tượng có thể có cả phương thức trừu tượng và không trừu tượng.

Chỉ có thể có các phương thức trừu tượng.

Có thể có nhiều biến: biến final, non-final, static và non static.

Chỉ có các biến static và final.

Không hỗ trợ đa kế thừa.

Có hỗ trợ đa kế thừa.

21. Một class chiếm bao nhiêu bộ nhớ?

Các class không sử dụng bộ nhớ. Chúng chỉ phục vụ như một template mà từ đó các items được tạo ra.

22. Có phải lúc nào cũng cần tạo đối tượng từ class không?

Không. Nếu class cơ sở bao gồm các phương thức non-static, thì một đối tượng mới được tạo ra. Nhưng nếu class bao gồm các phương thức static, thì không cần thiết tạo đối tượng. Trong trường hợp này, bạn có thể sử dụng tên class để call trực tiếp các phương thức static đó.

23. Sự khác biệt giữa class và structure trong C++ là gì

Structure cũng tương tự như class, là một kiểu dữ liệu do người dùng định nghĩa, tuy nhiên cả hai có vài điểm khác biệt:

  • Trong một structure thì các thành phần được đặt thành chế độ công khai theo mặc định trong khi trong một class, các thành phần được đặt ở chế độ riêng tư.
  • Sự khác biệt nữa là structure được sử dụng để khai báo cấu trúc, còn class để khai báo một class trong C++.

24. Constructor (hàm tạo) là gì?

Constructor (hàm tạo) là một code block khởi tạo đối tượng mới vừa được tạo. Một hàm tạo giống như một phương thức thể hiện (instance method) nhưng nó không phải là một phương thức, vì nó không có kiểu trả về (return type). Nó thường có cùng tên với class nhưng trong một số ngôn ngữ có thể khác. Ví dụ:

  • Trong python, hàm tạo có tên là __init__.
  • Trong C++ và Java, hàm tạo được đặt tên giống như tên class.

25. Có mấy loại hàm tạo trong C++?

Phân loại phổ biến nhất bao gồm:

  • Hàm tạo mặc định (Default Constructor)
  • Hàm tạo không tham số (Non-Parameterized Constructor)
  • Hàm tạo được tham số hóa (Parameterized Constructor)
  • Hàm tạo sao chép (Copy Constructor)

26. Hàm hủy (destructor) là gì?

Là một phương thức được thực hiện khi đối tượng bị hủy.

Trong C++, tên hàm hủy cũng giống như tên class nhưng với ký hiệu dấu ngã ( ~ ) làm tiền tố.

Trong Python, hàm hủy có tên là __del__ .

27. Có thể overload hàm tạo trong một class không?

Có. Trên thực tế, hàm tạo mặc định, hàm tạo được tham số hóa và hàm tạo sao chép là các dạng overload của hàm tạo.

28. Có thể overload hàm hủy trong một class được không?

Không. Một hàm hủy không thể bị overload trong một class, chúng chỉ có thể tồn tại trong một class.

29. Hàm ảo (virtual function) là gì?

Hàm ảo là một hàm được sử dụng để override lên một phương thức của class cha trong class kế thừa. Nó được sử dụng để cung cấp abstraction trong một class.

Trong C++, một hàm ảo được khai báo bằng từ khóa virtual,

Trong Java, mọi phương thức công khai, non-static và non-final đều là một hàm ảo.

Các phương thức Python luôn là phương thức ảo.

30. Hàm thuần ảo là gì?

Hàm ảo thuần túy, còn được gọi là hàm trừu tượng, là hàm thành phần không chứa bất kỳ câu lệnh nào. Hàm này được định nghĩa trong lớp kế thừa nếu cần.

Như vậy, chúng ta đã vừa điểm qua 15 câu hỏi phỏng vấn còn lại về chủ đề OOP, nếu bạn vẫn chưa đọc P1 thì bạn có thể theo dõi tại đây.