Tìm hiểu Overriding và Overloading trong OOP
Difference between method overriding(Ghi đè) and overloading(Nạp chồng).
Trong OOP, Overriding và Overloading là 2 kỹ thuật giúp tạo nên Tính đa hình (Polymorphism), mộ trong những sức mạnh của lập trình hướng đối tượng. Bài viết trong mục này sẽ tìm hiểu về khái niệm, cách dùng và tác dụng của 2 kỹ thuật trên.
Trong phạm vi bài viết này chúng ta chỉ đề cập đến 2 kỹ thuật này trong Method. Trong lập trình cấu trúc C, chúng ta không thể nào khai báo các function(method) trùng tên, nhưng trong OOP chỉ cần áp dụng hai kỹ thuật này, chúng ra hoàn toàn có thể làm được điều đó.
Overriding
Khi sử dụng Overriding, bạn đã thay đổi hành vi của method mà nó override. Nói đơn giản là nó đã ghi đè nội dung lên method trước đó.
Lưu ý: Method này phải được khai báo giống hệt với method trước (nó có thể là lớp base hoặc lớp dẫn xuất trước) trước tên method, đối số truyền vào và kiểu trả về.
- Overriding thường được sử dụng trong method ở lớp con.
Một số quy tắc sử dụng phương thức overriding:
* Các phương thức được mô tả static thì không overriden nhưng được mô tả lại.
(có một bài viết về static method trong mục Programming Technique - bạn có thể tìm nó để đọc)
* Các phương thức không được kế thừa sẽ không được overriden (hiển nhiên).
ví dụ như các Method được để chế độ private thì nó sẽ k được kế thừa -> thì sẽ k được overriden.
* Chỉ có thể override các phương thức không phải final (java) được khai báo là public hoặc protected. -> cái này nói về Java, bạn có thể bỏ qua nếu chỉ lưu ý về C++
Overloading
Overloading đơn giản chỉ để tạo ra các method cùng tên trong cùng một Class.
Lưu ý: Nhưng các method đó phải khác nhau về đối số đầu vào (argument) hoặc kiểu trả về.
– Các method với kỹ thuật này không ghi đè mà cùng tồn tại song song.
/*-----------------------------------------------------------------------------------------------------*/
Phân biệt sự khác nhau giữa overloading, overriding và hidding
1. Overloading và hidding
a. Overloading:
Trong C++, overloading đơn giản là sử dụng cùng tên hàm cho các hàm có chức năng khác nhau trong cùng 1 phạm vi (class level,…).
Giả sử chúng ta có 3 hàm sau được khai báo trong cùng 1 tập tin.
Giả sử chúng ta có 3 hàm sau được khai báo trong cùng 1 tập tin.
bool process( Credit & );
bool process( Acceptance & );
bool process( OrderForm & );
rõ ràng 3 hàm này được overloading .
bool process( Acceptance & );
bool process( OrderForm & );
rõ ràng 3 hàm này được overloading .
Trình biên dich phân biệt các hàm trên như thế nào?.
Thực tế trình biên dịch sẽ phân biệt các hàm trên giữa vào các tham số được sử dụng để gọi hàm.
Trong C++, tên hàm được hiểu là sự kết hợp giữa định danh của hàm (the function’s identifier)(trong ví dụ trên là process) và kiểu của tham số lúc khai báo.
Khi ta nhúng các hàm trên vào trong 1 lớp:
class Processor {
public:
virtual ~Processor();
bool process( Credit & );
bool process( Acceptance & );
bool process( OrderForm & );
};
public:
virtual ~Processor();
bool process( Credit & );
bool process( Acceptance & );
bool process( OrderForm & );
};
Các hàm này vẫn overloading theo cách giống như trên .
Bây giờ chúng ta sẽ thực hiện kế thừa lớp trên như sau:
Bây giờ chúng ta sẽ thực hiện kế thừa lớp trên như sau:
class MyProcessor : public Processor {
public:
bool process( Rejection & );
};
public:
bool process( Rejection & );
};
Tại đây 3 hàm của lớp base Processor chúng bị ẩn đi nên chúng sẽ không bị overload trong lớp dẫn xuất.
Lưu ý: Cơ sở là hàm base, hàm cha. dẫn xuất là hàm có. chỉ có 1 hàm cở sở nhưng có nhiều hàm dẫn xuất
b. Hidding:
Hidding là gì?
Trong class MyProcessor 3 hàm trong lớp Processor đều bị ẩn đi (lớp dẫn xuất bình thường không thế nhìn thầy(tuy nhiên, có thể gọi băng cách chỉ đến lớp cha ) ). Ta hiểu rằng bị ẩn là có tồn tại có thể gọi đến nhưng măc định là không biết đến, không đề cập.
Hidding có tác dụng gì?
Chúng ta có các thuộc tính và các phương trình trùng tên trong lớp cơ sở và lớp dẫn xuất, tuy nhiên chúng lại không có liên quan đến nhau thì hidding giúp chúng vẫn hiện diện, có thể gọi đến và không xảy ra lỗi.
2. Overriding
Overriding xảy ra khi nào?
Overrding chỉ xảy ra khi lớp cơ sở có sự xuất hiện của hàm ảo (từ khóa Virtual cho method cần được override).
Overriding không có gì liên quan đến overloading cả. 1 lớp cở sở không có hàm ảo thì không thế xuất hiện overriding mà chỉ có hidden.
class Doer {
public:
virtual ~Doer();
bool doit( Credit & );
virtual bool doit( Acceptance & );
virtual bool doit( OrderForm & );
virtual bool doit( Rejection & );
};
public:
virtual ~Doer();
bool doit( Credit & );
virtual bool doit( Acceptance & );
virtual bool doit( OrderForm & );
virtual bool doit( Rejection & );
};
class MyDoer : public Doer {
private:
bool doit( Credit & ); // #1, hides
bool doit( Acceptance & ); // #2, overrides(có từ khóa virtual ở lớp base)
virtual bool doit( Rejection & ) const; // #3, doesn't override(tham số truyền vào là con trỏ hằng this khác với con trỏ this)
double doit( OrderForm & ); // #4, an error(hàm này bị lỗi vì nó cũng được overriding tuy nhiên kiểu trả về của chúng khác nhau vì “the function signture không được phân biệt bằng kiểu trả về”)
};
private:
bool doit( Credit & ); // #1, hides
bool doit( Acceptance & ); // #2, overrides(có từ khóa virtual ở lớp base)
virtual bool doit( Rejection & ) const; // #3, doesn't override(tham số truyền vào là con trỏ hằng this khác với con trỏ this)
double doit( OrderForm & ); // #4, an error(hàm này bị lỗi vì nó cũng được overriding tuy nhiên kiểu trả về của chúng khác nhau vì “the function signture không được phân biệt bằng kiểu trả về”)
};
Overrding và access level:
Hàm được đánh nhãn là #2 bị overriding tương ứng với chức năng của lớp cơ sở.
Chúng ta chú ý rằng overriding ko bị ảnh hưởng bởi acess level (public,private,protected) khi kế thừa.
Điều đó có nghĩa là lớp cở sở là public và lớp dẫn xuất là private thì vấn xảy ra overriding. Thông thường hàm bị overriding sẽ có cùng acess level với hàm tương ứng ở lớp cở sở.
class Visitor {
public:
virtual void visit( Acceptance & );
virtual void visit( Credit & );
virtual void visit( OrderForm & );
virtual int numHits();
};
class ValidVisitor : public Visitor {
void visit( Acceptance & ); // overrides
void visit( Credit & ); // overrides
int numHits( int ); // #5, nonvirtual, khác nhau về đối số
};
public:
virtual void visit( Acceptance & );
virtual void visit( Credit & );
virtual void visit( OrderForm & );
virtual int numHits();
};
class ValidVisitor : public Visitor {
void visit( Acceptance & ); // overrides
void visit( Credit & ); // overrides
int numHits( int ); // #5, nonvirtual, khác nhau về đối số
};
Trong trường hợp này người thiết kế cho phép tùy biến cách “cư xử” cửa lớp cở sở, nhưng muốn người sử dụng sử dụng lại interface của lớp cở sở. Người thiết kế sẽ khai báo lớp base với hàm có access level là public và lớp dẫn xuất cò hàm tượng với những với access level là private
Ý nghĩa của từ khóa virtual và tính virtual của hàm dẫn xuất:
Chú ý rằng lớp dẫn xuất (lớp kế thừa cái lớp trước đó) có hay không từ khóa virtual chỉ là tùy chọn không bắt buộc, ý nghĩa của ý nghĩa của hàm sẽ không thay đổi.
Có 1 quan niệm sai lầm phổ biên là khi không xuất hiện từ khóa virtual ở lớp dẫn xuất thì nó sẽ ngăn cản thì nó sẽ ngăn cản overriding ở các lớp dẫn xuất tiếp theo
-> Đây là một ý nghĩ sai lầm.
hàm MyValidVisitor::visit( Credit & ) sẽ bị overriding bởi hàm tương ứng ở lớp dẫn xuất ValidVisitor().
class MyValidVisitor : public ValidVisitor {
void visit( Credit & ); // overrides
void visit( OrderForm & ); // overrides
int numHits(); // #6, virtual, overrides Visitor::numHits
};
class MyValidVisitor : public ValidVisitor {
void visit( Credit & ); // overrides
void visit( OrderForm & ); // overrides
int numHits(); // #6, virtual, overrides Visitor::numHits
};
Nó cũng hoàn toàn hợp lệ cho những lớp dẫn xuất ở xa hơn hàm MyValidVisitor::visit( OrderForm & ) overriding hàm tương ứng ở lớp Visitor.
Các lớp dẫn xuất cũng bị override với những hàm của lớp cở sở “ông,..”.mà những lớp đó không được nhìn thấy trong phạm vi lớp dẫn xuất ”chú”. Ví dụ hàm MyValidVisitor::numHits vẫn override hàm Visitor::numHits mặc dù hàm Visitor::numHits bị ẩn ở lớp ValidVisitor.
Kiểu trả về “hiệp biến” (covariant return types) và overriding:
Trong phân tích trên: MyDoer::double doit( OrderForm & ), xảy ra lỗi khi trong thời gian dịch vì kiểu trả về của hàm bị overriding không tương xứng với hàm ở lớp cở sở.
Tuy nhiên có 1 ngoại lệ nếu kiểu trả về là con trỏ đến lớp 2 lớp có quan hệ với nhau (covariant return types)
class B {
virtual B *clone() const = 0;
};
class D : public B {
D *clone() const;
};
Hàm clone ở lớp dẫn xuất bị override là hoàn toàn hợp lệ.
Trong phân tích trên: MyDoer::double doit( OrderForm & ), xảy ra lỗi khi trong thời gian dịch vì kiểu trả về của hàm bị overriding không tương xứng với hàm ở lớp cở sở.
Tuy nhiên có 1 ngoại lệ nếu kiểu trả về là con trỏ đến lớp 2 lớp có quan hệ với nhau (covariant return types)
class B {
virtual B *clone() const = 0;
};
class D : public B {
D *clone() const;
};
Hàm clone ở lớp dẫn xuất bị override là hoàn toàn hợp lệ.
source: http://diendan.congdongcviet.com/threads/t199237::phan-biet-su-khac-nhau-giua-overloading-overriding-hidding.cpp
0 comments :
Post a Comment