Bài 7: Đa hình

Gi

i thi u

ả •   Đa hình là kh  năng cho phép:

c  nh  ngh a  các  ph

ươ ố

ĩ ể

ệ đị

ng  th c  trùng  ể ả ng và ki u tham s , cùng ki u tr   ế ớ ng  th c  trùng  nhau  c a  các  l p  k   ươ

ứ ự ạ

ớ đượ đị     Cho  phép  các  l p  ố ượ nhau: cùng tên, cùng s  l ươ ề v .  Vi c  nh  ngh a  ph ọ ừ th a nhau còn

ủ ng th c.

ĩ đượ c g i là s  n p ch ng ph

ươ

đố ượ i t

ứ ủ ớ ươ

ự ươ ng th c c a l p t

đ ng  ang  ng

ng th c trùng tên, d a vào  ệ ả

ứ ẽ ự ng trình s  th c hi n ph ế

ươ đ

ọ   Khi g i các ph ọ g i mà ch ứ ng, và do  ó, s  cho các k t qu  khác nhau.

ườ ớ ươ

ụ ươ

ự ứ

Ví d : Xây d ng l p ng có ph

ng th c Nhap() và ph

ớ i, l p sinh viên, l p giáo viên cùng  ng th c Xuat().

để ử

ươ

ơ ở

ế  x  lý  ư ng  c a  t t  c   các  l p  trong  m t  phân  c p  nh   i mà

ng trình  ộ đ ệ đượ i p

ấ ử đ c g i

 Nh  v y  a hình là kh  n ng cho phép vi t ch ư ậ đ ổ t ng  quát  các  đố ượ i t các  ầ không c n bi t

đố ượ i  t ủ ớ ng c a l p c  s . Do v y m t thông  ậ ế đố ượ i t

ả ă ủ ấ ả ộ ậ ộ ớ ng nh n thu c l p nào.

ươ

Các ph

ứ ả ng th c  o

Xét ví dụ ớ

ươ

ng th c xuat() ỏ ể

ố ượ ố ượ ố ượ

ể ng ki u A ể ng ki u B ể ng ki u c

ươ

ứ ả

3 l p A,B,C đ u có ph A  *p, *q, *r;   // p, q, r là con tr  ki u A A   a;    //  a là đ i t B   b;    //  b là đ i t C   c;    //  c là đ i t //­­­­­­­­­­­­­­­­­ p =  &a ; q =  &b ; r =   &c ; //­­­­­­­­­­­­ p­>xuat(); q­>xuat(); r­>xuat(); ề ả (cid:222) C  ba câu l nh đ u g i đ n A::xuat() (cid:222) Gi

ọ ế ự i pháp:  Xây d ng xuat() là ph

ng th c  o

ươ

Các ph

ứ ả ng th c  o

ả ử

ươ  s  các l p này đ u có ph ứ

ả ử ể ị

ng th c xuat(). ả

ớ ơ ở •   Gi  s  A là l p c  s . ấ ớ •   B,C,D là l p d n xu t. ề •   Gi ươ •   Đ  đ nh nghĩa các ph

ứ ng th c này là  o có 2 cách:

đề ủ

c a

ươ

ĩ ớ

ơ ở

đị

ph

đề

bên

ặ o     Ho c  thêm  t   khoá  virtual  vào  dòng  tiêu  ng th c bên trong  nh ngh a l p c  s  A. ặ o     Ho c  thêm  t   khoá  virtual  vào  dòng  tiêu  đị

ừ ĩ ủ

ấ ả

trong  nh ngh a c a  t t c  các l p A, B, C và D

ươ

Các ph

ứ ả ng th c  o

ộ ấ

ườ ậ

i  l p

ủ ớ

•   Khi  xây  d ng  m t  c u  trúc  cây  phân  c p,  ng trình chu n b  các hành vi chung c a l p đó.

ẽ ượ

ể ể ệ

•   Hành  vi  giao  ti p  chung  s   đ

c  dùng  đ   th   hi n   đó  ộ

ế ư ứ ả

ươ

cùng hành vi, nh ng có các hành đ ng khác nhau  là ph

ng th c  o.

ụ ọ

Ví d : Đ c thêm ví d  trang 122 ­ giáo trình LTHĐT

ươ

Các ph

cout< <"class Base"<

ứ ả ng th c  o class Derived : public Base {        public:             virtual void Display()            {                 cout<<"class Derived"<

n ph

ứ ặ ớ

đế ủ ớ

ươ

ng trình.

ươ //(c a l p Base ho c l p  Derived) //tùy vào lúc ch y ạ ch }

int main() {      Base *B=new Base;      Derived *D=new Derived;      B­>Display(); //Base::Display()      D­>Display(); //Derived::Display()      Show(B); //Base::Display()      Show(D); //Derived::Display()      return 0; }

class Base {      public:           virtual void Display()          {            } }; void Show(Base *B) {      B­>Display(); //Con tr  B ch ng th c Display()

ươ

Các ph

ứ ả ng th c  o

ế

ươ

ng trình:

•   K t qu  khi ch y ch ả

Gi

i thích:   N u không có khai báo virtual cho ph ế ng th c  ệ khi đó l nh Show(D) trong hàm main() s  g i đ n  ố ượ (vì đ i t

ứ Base::Display()  ươ ẽ ọ ế Base::Display()  ố ượ ủ ớ ơ ở ủ ớ ẫ ấ ng c a l p d n xu t cũng là đ i t ng c a l p c  s ).

ờ ng  th c virtual  cho  ph

ự ươ ứ ọ

ươ ng th c  ộ ố

ể ủ ố ươ ề ứ Base::Display()  nên  s  ẽ ộ ứ Base::Display() m t cách c ng  Show() mà tùy thu c vào ki u c a tham s  vào lúc  ng  trình.  (  khi  truy n  tham  s   B  thì  Base::Display()

• Nh   khai  báo  ệ không th c hi n g i ph ắ nh c trong hàm  ạ ch y  ch ượ ọ đ

ượ ọ ề c g i, khi truy n D thì Derived::Display() đ c g i).

ươ

Các ph

ứ ả ng th c  o

•  Gi

ơ ế i thích c  ch :

ẽ ấ ủ

ủ ớ ả

ớ ơ ở virtual trong l p c  s , trình biên  ớ ơ ở ẫ ng  c a  l p  c   s   và  l p  d n  ứ ả ươ ỉ ế ng  th c  o

ấ  Khi nh n th y có khai báo  ỗ ố ượ ị d ch  s   thêm  vào  m i  đ i  t ỏ xu t  c a  nó  m t  con  tr   ch   đ n  b ng  ph (virtual function table), con  tr  có tên vptr.

ươ

ứ ả

ơ

ng th c  o là n i ch a các con tr  ch  đ n đo n

ị ứ

ươ

ỉ ế ứ ả

ứ ớ

ả  B ng ph ươ ch

ng trình đã biên d ch  ng v i các ph

ng th c  o.

ỗ ớ ứ ả

ứ ả

ng th c  o.  ươ ế ạ

ệ ạ ươ ỉ ậ ng  c a  l p.  Đ n  khi  ch ớ ượ ố ượ ủ ắ ầ ng th c  o khi b t đ u có  ươ ng  trình  ch y,  ố ế c  n i  k t  và  thi ng  m i  đ

M i l p có m t b ng ph ươ ộ ả ả ị  Trình biên d ch ch  l p b ng ph ủ ớ ố ượ vi c  t o  đ i  t ứ ả ph ng  th c  o  c a  đ i  t hành thông qua con tr  vptr

ươ

Các ph

ứ ả ng th c  o

•  Gi

ơ ế i thích c  ch : ụ

Xét ví d  trên: Hàm Show(D).

ể ể ổ ng ố ượ D  thu c  l p

ộ ố ượ

ộ ố ượ Đ i  t thành  m t  đ i  t ố toàn gi ng m t đ i t ị ộ ớ Derived  tuy  b   chuy n  đ i  ki u  ộ ớ Base  nh ng  nó  không  hoàn  ư ng  thu c  l p  ố ng c a ủ Base chính c ng nh ư B.

ỉ ế ươ ứ ả ị B ch  đ n v  trí trên b ng ph

ỏ o  ng  v i  ph

ng  th c  ẫ ng th c  ứ Base::Display(),  trong  khi  con  tr  ỏ ứ th c ươ trong  D  v n

ế ch   đ n  ph ể còn  ị ỉ ể Con tr  vptr trong  ớ ả ứ ươ vptr  Derived::Display() cho dù D b  chuy n ki u thành ng  Base.

ậ ế ươ ệ l nh: ng ứ th c ọ Show(D);g i  đ n  ph

    Do  v y  Derived::Display()

ươ

Các ph

ứ ả ng th c  o

ươ

ứ ả

ư •  Đ c tr ng c a ph

ng th c  o.

ươ

ứ ả

ươ

•  Ph

ng th c  o không th  là các ph

ứ ng th c tĩnh.

ướ

•   Không  c n  thi

c

t  ph i  ghi  rõ  t ươ

khóa  virtual  tr ấ

ứ ả

ế đ nh nghĩa m t ph

ả ng th c  o trong l p d n xu t.

ươ

•  Khi m t ph

ứ ng th c đ

c đ nh nghĩa là  o, t

ả ị

ả ề

ấ ề ế

ơ

ươ ươ

ẽ ể

ừ ớ ượ ộ  l p  ố ấ ề ơ ở ế ớ c   s   đ n  l p  d n  xu t  đ u  ph i  đ nh  nghĩa  th ng  ố ể nh t  v   tên,  ki u  tr   v   và  danh  sách  các  tham  s .  ứ ấ ị N u  ta  s   xu t  đ nh  nghĩa  ph ng  th c  khác  đi  thì  ứ ng th c khác. trình biên d ch s  hi u đó là ph

ớ ơ ở ừ ượ

L p c  s  tr u t

ng

ố ượ

ể ạ

ế ế ướ t k  h

ng đ i t

ườ ậ i l p trình ph i đoán tr ọ

ệ ố ướ ự ợ

ả ng, đ  t o h  th ng ph   ả c s  phát   đó l a ch n nh ng thành viên phù h p cho

Trong quá trình thi ế ừ ệ h  mang tính k  th a cao ng ự ừ ủ ấ ể tri n c a c u trúc t ớ l p trên cùng.

ớ t k  các l p có các ph

ố ượ

ể ạ

ạ ố ượ   Đ  tránh tình tr ng xây d ng các đ i t ươ ế ế cho phép thi và cũng không th  t o ra đ i t

ộ ng lãng phí b  nh , C++  ả ứ ả ng th c  o không làm gì c ,  ủ ớ ng c a l p đó.

ừ ượ

 Nh ng l p nh  v y g i là l p tr u t ư ậ

ng.

ớ ơ ở ừ ượ

ng

L p c  s  tr u t ớ ơ ở ỉ

•   Là l p ch  dùng làm c  s  cho các l p khác.

ượ

ộ ố ượ

ở ạ

c kh i t o m t đ i t

ộ ớ ng thu c l p tr u

ượ

•   Không đ ng.

t

ừ ượ

ươ

ng là các ph

ng

•   Các ph ứ ả

ứ ủ ớ ng th c c a l p tr u t ầ

ươ th c  o thu n túy.

ươ

virtual  void  tên_ph

ứ ng_th c() = 0 ;

•   B t k  l p nào d n xu t t

ấ ừ ộ ớ ớ ở ừ ượ  m t l p c  s  tr u t

ầ ả

ươ

ạ ấ ả

ng  ng th c thu n  o mà

t c  các ph

ẫ i t

ấ ỳ ớ ả ị ph i đ nh nghĩa l ừ ưở nó th a h

ng.

ớ ơ ở ừ ượ

L p c  s  tr u t

ng

ư ả ớ ơ ể ạ ọ ớ ủ ượ ạ ộ ặ ắ ở ấ c t o ra kh p n i đ  t o b  m t chung cho m i l p c a

ứ ả ượ ườ ươ ể Trong cây phân c p trên không ph i l p nào cũng c n hàm print(),  nh ng nó đ cây  phân c p.ấ   A::Print() th ng th c  o đ  có đ c tính đa hình. ng là ph

ớ ơ ở ừ ượ

L p c  s  tr u t

ng

Khi đó v i hàmớ

void Show(A* a) {

a­>Print();

ể ọ ế ố ượ ơ ủ ợ ố

ủ ể ứ ư ế ị

đố ượ i  t

ầ ả ươ ự ớ ộ ớ ng  thu c  l p  A,  ta  ứ ng  th c  thu n  o ạ ng  v i  các  ph

class A {

public:       virtual void Print() = 0;

};

ừ ư } A, B, C, D ho c ặ E) mà  ng  đ  ki u cho nó ( ta  có th  truy n  đ i  t ể ẫ v n  g i  đ n  đúng  phu ng  th c  Print()  phù  h p,  dù  ki u  c a  đ i  ẫ ượ t. ng lúc biên d ch v n còn ch a bi t ạ Để   tránh  trình  tr ng  vô  tình  t o  ra    ượ ớ ườ th ng  xây  d ng  l p  tr u  t (pure virtual function) nh  sau:

ụ Xem ví d  trang 126­ giáo trình LTHDT

ớ ơ ở ừ ượ

L p c  s  tr u t

ng

Ø Chú ý:

ể ạ ừ ượ

ư ộ ố ượ ộ

ộ ả ộ ớ ố ượ

ớ ị l p tr u t

ế ừ ừ ớ ầ ả ứ ầ ả ủ ớ ơ ở ẫ ấ ừ ượ ng chúng ta không đ nh  ẽ ế ừ ng  th c  thu n  o,  do  tính  k   th a  nó  s   bao  hàm  ẽ ớ ng th c thu n  o c a l p c  s , nên l p d n xu t này s

ươ ứ ớ ng.

ừ ượ

ơ ở ừ ượ ừ ượ ớ ế ng)  chúng  ta  đ nh  nghĩa  thêm  m t  ph ấ ừ ớ ng, n u trong l p d n xu t (t   ươ ng

ẫ ộ ừ ượ ị ẽ ở ầ ả ứ ớ ớ ủ ớ ng c a l p tr u t ng,    Chúng ta không th  t o ra m t đ i t ỏ ỏ ế ớ ể ạ nh ng hoàn toàn có th  t o ra m t con tr  tr  đ n l p này (vì  ặ ỏ ng thu c l p) ho c là m t tham  con tr  không ph i là đ i t chi u.ế ế    N u trong l p k  th a t nghĩa  ph ươ ph ở tr  thành l p tr u t ị    Theo đ nh nghĩa l p tr u t ớ l p  c   s   tr u  t th c thu n  o khác, l p này cũng s  tr  thành l p tr u t ng.

ả ủ

ộ ớ

Các thành viên  o c a m t l p

ử ả Các toán t

ươ ng th c nên ta có th  đ nh

ả ử ụ ứ ạ ể ị  là  o, chú ý ki u c a toán h ng ph i s  d ng

ấ ử ả ể ủ ớ ơ ở ố b n ch t cũng là các ph ể ủ ử ả   o.

o: ử ả   Các toán t nghĩa các toán t ki u c a l p c  s  g c có toán t   Ví dụ

class A { … virtual A& operator + (A& T); virtual A& operator = (A& T); …   } Class B: public A {… virtual A& operator + (A& T); virtual A& operator = (A& T); …   }