【C++ Primer】类的多态

上一篇 / 下一篇  2012-07-12 13:17:34 / 个人分类:C++

51Testing软件测试网B"M*kj9^$h S

  一、概述51Testing软件测试网Y6`O@0k0U

3C"Hst-I"M%iciaw,P0  1)接口的多种不同的实现方式即为多态。

;[~(_IJ?eUs051Testing软件测试网c+v;nq} [

  2)多态性是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式 运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。多态性在C++中都是通过虚函数(Virtual Function) 实现的。

,@K D/w5GE0

4an C2J-\~0  3)关键点:多态还有个关键之处就是一切用指向基类的指针或引用来操作对象

PIi)|`dsbEI051Testing软件测试网,CH~2B5Q;k|

  二、示例51Testing软件测试网$tF$jfew

51Testing软件测试网CoLo4uA

  1)普通的对象操作方式

s)fo*\r9xRO051Testing软件测试网O1N!rlRG

N,Bl4DJ&@ P8@;VJ0
#include <iostream>
/m*v1n9R%p"F L0using namespace std;
3Q;~6|ESZgC$xD0class A{
)@zc4WF0public:51Testing软件测试网y;JD8b;_Q
 void print()51Testing软件测试网Dh3R-X/F$UL&}~
 {
pKBi7ey ZM0  cout<<"This is A"<<endl;
C._s d7t(`4w B0 }51Testing软件测试网 Z)nK'ZW%D/Bz h
};51Testing软件测试网"^F5Bs8m\4b\
class B:public A{
C8Xm5^"nD*B b!B/E*D5\#g0public:51Testing软件测试网@0YIAkI@v
 void print()
G6C"G7s0sw J(^0 {51Testing软件测试网\:j-n0Ld_
  cout<<"This is B"<<endl;51Testing软件测试网1TzXl%E`B
 }51Testing软件测试网 x7M^?)U px
};
kS I9a q-e,C3l7N9X0int main(){ //为了在以后便于区分,我这段main()代码叫做main1  
k.F%A j%a;O8rq+D,?.T0 A a;51Testing软件测试网.x9Ks&I puU
 B b;
+d3z OL[S{0 a.print();
N5u_ I V%h0 b.print();
bLb_/_w0}

5U0l*MxhZI\}}0  输出:This  is  A

J2T``i'm6`Qjs|[0

5h,n)s)S4})E(FqS0     This  is  B

yZ.b6e%T/zDW5\0

[YOz+N%hQ+[0  2)按照多态的操作对象方式:通过父类对象来操作子类对象51Testing软件测试网0ynt5D:S9Fn|_.v Y

4]$Z o?gwu|h051Testing软件测试网G#K6v:^ea]sm

#include <iostream>
1R%T mD1jeSn0using namespace std;
1^R+u T?D]5p0f0class A{51Testing软件测试网)K-xHxW%O G
public:
Y&v2Pt v:M9N`S8T6s8Mf0 void print()51Testing软件测试网)y&T/L T(lA _Et]
 {
q_4T;VvLN)pS [0  cout<<"This is A"<<endl;51Testing软件测试网z'Sqk#_5PQ
 }
/l)T~VH@&|0};51Testing软件测试网!L&A}Wp/\^ak
class B:public A{
-P(dTb$[2t cE0public:
8E5W's*vB {p y(a$z0 void print()51Testing软件测试网Gl1~$iu
 {
e(J8zd Y D5~0  cout<<"This is B"<<endl;
2w*p5]F)D)Z$ri3J0 }51Testing软件测试网$c\5{E,e c.MK t
};
&ay2j*~;_`#tA0int main(){ //通过父类来操作子类
o"?7s6C-V$TyuH2d0 A a;51Testing软件测试网O4c.ElM@B[
 B b;
?3UE-N X9t0 A* p1=&a;51Testing软件测试网6E(C-M*hh3HUgY U
 A* p2=&b;
:A8Jl i+oy[0 p1->print();51Testing软件测试网,qh$Ib ^pA j&_
 p2->print();
Z\A6DXnW0}

j I2G~C&NLv?0  输出:This  is  A51Testing软件测试网w~4G*`C2d M#J

51Testing软件测试网G5x-Jx(U;QE

     This  is  A

`@z[Z)~0

;m4I!h[6Q3X6|\(L0  这跟我们预期的不一样。

*zYr\9L0 3)采用多态,就是在父类函数前面加上virtual

/Fr^Pms9q^S,S0  根据不同的类对象,调用其相应的函数,这个函数就是虚函数51Testing软件测试网)Me"E*MJV SV W

w$CR` Kv W7Uu0

/Ja*ShEuil0
#include <iostream>51Testing软件测试网%m;y"fl'v
using namespace std;51Testing软件测试网 Ae9WCW V K
class A{51Testing软件测试网,||F^&Rw5C
public:
6hl-C\ j0 virtual void print()
L1o M7V#We!L'AmC0 {
rO x kP0  cout<<"This is A"<<endl;
)]d6EXhK0 }
9| [1T#ve0};51Testing软件测试网 `3PG0N-{HC
class B:public A{51Testing软件测试网j\zM$} b
public:
V{:T b-NFKc0 void print()
aHzvx&[0 {51Testing软件测试网8jz'Wl]i+G
  cout<<"This is B"<<endl;51Testing软件测试网,W5@r6X9\
 }
1Uxd2U5o5`C0};51Testing软件测试网$lh0coV
int main(){ //通过父类来操作子类51Testing软件测试网,g5Td*t W ` ?{
 A a;
jZe+r xi2]#KR0 B b;
qOA!H7V @6oU0 A* p1=&a;51Testing软件测试网5E'Q8ZieuCK
 A* p2=&b;51Testing软件测试网IU1_4J,w yCs
 p1->print();
#Yd\i5g }}VC+?0 p2->print();51Testing软件测试网,KD}%q-m(]g
}

3|l] ^ D u!h(k#}0  三、虚函数进阶51Testing软件测试网8KE,?1cd @xC

51Testing软件测试网w Y2P0I5B

  void (A::*fun)(); //定义一个函数指针

9@.`l'dx`b051Testing软件测试网 Vm S8W4{}O

  A *p=new B;

1L]NL}OyL0

z O.b`3t"T)s7k\I4\}0  fun=&A::fun;//是真正获得虚函数的地址吗? 其实间接获得虚函数地址的一段代码的地址

xEA*i g,m%W5P0

8O|)U/V}0

v b V.dTT&C0

qX&wYEvO0g NU,i0#include <iostream>51Testing软件测试网8t7o{'czB2o1|[
using namespace std;
51Testing软件测试网6Es@(_G3JC"H-`

,sbGV K"Y0class A{51Testing软件测试网HpI/`!s'}&J
public:
egrbG0 virtual void fun()
;Qm |}A;D6?v$c1v!A0 {51Testing软件测试网|8? u6g(Zn
  cout<<"A::fun"<<endl;51Testing软件测试网eR JR9rw5a-Q
 }
i2`G4X)^ h0 virtual void fun2()51Testing软件测试网8W @ Nv!D!~T8Q
 {51Testing软件测试网pK C*T m\n
  cout<<"A::fun2"<<endl;
-sG M4|"mK0 }51Testing软件测试网 e$O9Bc;k \ p2z
};51Testing软件测试网1@ h |q*~
class B:public A{
&H/U4gp8~5n%[$r B0public:
NA\Xt)c,|Q3J V0 void fun()51Testing软件测试网y5c\1vl:n`M
 {
J"VSjS'dG0  cout<<"B::fun"<<endl;
)RaoWU7[Gt0 }
C\Dw?(yH0 void fun2()
N`W9V'c{0 {
W3v$Dr"Cb~HU0   cout<<"B::fun2"<<endl;51Testing软件测试网u V^5n/b*w!OT
  }
:Aod+e1j;[ g5V?0};51Testing软件测试网;~ O8C8Pf(I,Oo
void CallVirtualFun(void *pThis , int  index=0)51Testing软件测试网9RZe5Lbgf}8ro
{
s?tBFQ{0_&EK0 void (*funptr)(void*);
"z;z)c+].Ec0 long lVptrAddr;51Testing软件测试网7R?7{ebVj-UQ2_4L
 memcpy(&lVptrAddr,pThis,4);
S(w-xB#B0Wo#l0 memcpy(&funptr,reinterpret_cast<long*>(lVptrAddr)+index,4);
^!B#z5}2c4P:ak/k0 funptr(pThis);51Testing软件测试网q'QB:n.C*D9W~
}
(BqL&U'ra?0int main()
/oB-Ftw:L6a q0{

-c0Ua#g#y:SA051Testing软件测试网&G%~:Z+|.{}&r

 void (A::*fun)(); //定义一个函数指针   
@;k(? tX,k$H b0XH7m7bC0 A *p=new B;
1BPl e:JFK0 fun=&A::fun;//是真正获得虚函数的地址吗? 其实间接获得虚函数地址的一段代码的地址51Testing软件测试网oF9ho} i(Hc
 (p->*fun)();//B::fun
c,d|3{;NL)t0 fun = &A::fun2;
Xl2jdvH2IU&p DF0 (p->*fun)();//B::fun2
MhdH,O0 51Testing软件测试网 E@ Jq+WFO
    CallVirtualFun(p); //调用虚函数p->fun()51Testing软件测试网o2P&y G!dC
 CallVirtualFun(p,1);//调用虚函数p->fun2()51Testing软件测试网8v&^0fq#C1~H} O"D
 delete p;51Testing软件测试网Oj6|![M3Q3l(~
 system("pause");
4C%L8i)?(Sk%\0 return 0;
4e ^$\s}0}
51Testing软件测试网4E9um_B5o I

51Testing软件测试网Hc.`%Wg$TH{Z[

  四、补充重要知识51Testing软件测试网kEU Yg?_6t

j+?7Y {,R'B-o-sK0  实例化类的虚函数必须有定义,原因如下:有虚函数作为成员函数的类, 它的实例化-对象, 在运行过程分配到的内存不止是它的成员数据, 还有一个指向该类虚函数表(vtable)的指针, 虚函数表中的每个数据项都是一个虚函数的入口地址;51Testing软件测试网/dWU4@rFpu3XS

51Testing软件测试网8Ox eN-x s

  如果一个对象的虚函数只有声明而没有实现, 就会出现这个虚函数表找不到本应作为其数据项之一的某函数的入口地址, 虚函数表在运行前不能装载完成, 所以产生连接错误!

Aqk3lw#O!J3k.V o6S0

-fSkV:If:D&?0相关链接:

RTdT8~(IX051Testing软件测试网s$F2\Lf6m9K

【C++ Primer】内联函数和外联函数

5q Ln9Xj3nQ0

TAG:

 

评分:0

我来说两句

Open Toolbar