C++之多态
来源:互联网 发布:app软件大全 编辑:程序博客网 时间:2024/04/30 09:59
多态性就是不同对象收到相同消息时,产生不同的动作。用一个名字定义不同的函数,这些函数执行不同但又类似的操作,即用同样的接口访问功能不同的函数,实现“一个接口,多种方法”。
C++支持的多态性分为编译时多态性和运行时多态性。其中编译时多态性主要通过函数重载和操作符重载来实现,而运行时多态通过继承和虚函数来实现。
1虚函数
1.1引入派生类后的对象指针
使用:
1 #include<iostream> 2 using namespace std; 3 4 class my_base 5 { 6 int a,b; 7 public: 8 my_base(int x,int y) 9 {10 a=x;11 b=y;12 }13 14 void show()15 {16 17 cout<<"my_base--------"<<endl;18 cout<<a<<" "<<b<<endl;19 }20 21 };22 23 class my_class:public my_base24 {25 26 int c; 27 public:28 29 my_class(int x,int y,int z):my_base(x,y)30 {31 32 c=z;33 }34 35 void show()36 {37 38 cout<<"my_class----------"<<endl;39 cout<<"c="<<c<<endl;40 }41 };42 43 void main()44 {45 46 my_base mb(50,50),*ptr;47 my_class mc(10,20,30);48 ptr=&mb;49 ptr->show ();50 ptr=&mc;51 ptr->show ();52 53 }
运行结果如下:
引入派生类后,使用对象指针应该主义的几个问题:1)声明为指向基类对象的指针可以指向它的公有派生对象,但不允许指向它的私有派生的对象。2)不能将一个声明为指向派生类对象的指针指向其基类的对象。3)声明为指向基类对象的指针,当其指向公有派生类对象时,只能用它来直接访问从基类继承来的成员,而不能直接访问公有派生类中定义的成员。
1 对于3)的说明: 2 3 Class A{//... 4 Public: 5 Void print1(); 6 }; 7 8 Class B: Public A{//.... 9 10 Public:11 Void print2();12 };13 14 Void main()15 {16 17 A op1,*ptr;//定义基类A的对象op1和基类指针ptr18 B op2;19 Ptr=&op1;20 Ptr->print1();21 Ptr=&op2;22 Ptr->print1();23 Ptr->print2(); //错误,不能访问派生类中定义的成员函数print2()24 }
如果需要访问其公有派生类中的特定成员,可以将基类指针用显式类型转换为派生类指针。错误语句可以改写为:((B*)ptr)->print2(); 外层括号表示对ptr强制转换,而不是返回类型。
1.2虚函数的定义和使用
使用虚函数,实现动态调用功能。多态性实现了在基类定义派生类所拥有的通用接口,而在派生类定义具体的实现方法。虚函数的定义在基类中进行,在需要定义为虚函数的成员函数的声明中冠以virtual关键字,从而提供一种接口界面。
定义方法:
Virtual 函数类型 函数名(形参列表)
{函数体}
1 #include<iostream> 2 3 using namespace std; 4 5 class parent 6 7 { 8 9 protected: 10 11 char version; 12 13 public: 14 15 parent() 16 17 { 18 19 version='A'; 20 21 } 22 23 virtual void print() 24 25 { 26 27 cout<<endl<<"The parent.version "<< version; 28 29 } 30 31 }; 32 33 class derived1:public parent 34 35 { 36 37 private : 38 39 int info; 40 41 public: 42 43 derived1(int number) 44 45 { 46 47 info=number; 48 49 version='1'; 50 51 } 52 53 void print() 54 55 { 56 57 cout<<endl<<"The derived1 info:"<<info<<" version "<<version; 58 59 } 60 61 }; 62 63 class derived2:public parent 64 65 { 66 67 private : 68 69 int info; 70 71 public: 72 73 derived2(int number) 74 75 { 76 77 info=number; 78 79 } 80 81 void print() 82 83 { 84 85 cout<<endl<<"The derived2 info:"<<info<<" version "<<version<<endl; 86 87 } 88 89 }; 90 91 void main() 92 93 { 94 95 parent ob,*op; 96 97 op=&ob; 98 99 op->print ();100 101 derived1 d1(3);102 103 derived2 d2(15);104 105 op=&d1;106 107 op->print ();108 109 op=&d2;110 111 op->print ();112 113 }
关于虚函数定义的几点说明:
1)在基类中利用关键字virtual可以将public和protected部分的成员函数声明为虚函数;
2)在派生类中对虚函数进行重新定义时,可以写virtual也不可以不写,当不写时遵循三个规则来判断(名称、参数个数和类型、返回类型);
3)虚函数重新定义时其函数原型必须与基类中全完相同;
4)只有通过基类指针访问虚函数时才能获得运行时的多态性,使用对象名和点运算符的调用方式是在编译时的静态连编;
5)一个虚函数无论被公有继承多少次,仍然保持其虚函数的特性;
6)虚函数必须是其所在类的成员函数,而不能是友元函数,也不能是静态成员函数。但虚函数可以在另一个类中被声明为友元函数;
7)构造函数不能是虚函数,但是析构函数可以。
虚函数与重载函数的区别:当普通函数重载时,其函数的参数或参数类型必须有所不同,函数的返回类型也可以不同。但是当重载一个虚函数时要求其原型完全相同。如果仅仅返回类型不同,其余相同,系统会给出出错信息;如果仅仅函数名相同,参数的个数类型或顺序不同,系统将它作为普通的函数重载,从而丢失虚函数的特性。
·多重继承与虚函数
1 #include <iostream.h> 2 3 Class base1{ 4 5 Public: 6 7 Virtual void fun() //定义为虚函数 8 9 {cout<<”--base1--”<<endl;} 10 11 };12 13 Class base2{14 15 Public:16 17 void fun()//定义为普通成员函数18 19 {cout<<”--base2--”<<endl;} 20 21 };22 23 Class derived:public base1,public base2{24 25 Public:26 27 Void fun()28 29 {cout<<”--derived--”<<endl;}30 31 };32 33 34 35 Void main()36 37 {38 39 Base1 *ptr1;40 41 Base2 *ptr2;42 43 Derived obj3;44 45 Ptr1=&obj3;46 47 Ptr1->fun();//此处调用派生类derived的fun()48 49 Ptr2=&obj3;50 51 Ptr2->fun();//此处调用的是基类base2的fun()52 53 }
1.3纯虚函数和抽象类
纯虚函数是一个在基类中说明的虚函数,它在该基类中没有定义,但要求在它的派生类中定义自己的版本,或重新说明为虚函数。
纯虚函数的一般形式:
Virtual 函数类型 函数名(参数表)=0;
如果一个类至少有一个纯虚函数,那么就称该类为抽象类。关于抽象类使用的一些注意:1)抽象类只能用作其他类的基类,不能建立抽象类对象;2)抽象类不能用作参数类型、函数类型或显示转换的类型,但可以声明指向抽象类的指针或引用,该指针可以指向它的派生类。3)如果在抽象类的派生类中没有重新说明纯虚函数,而派生类只是继承基类的纯虚函数,则这个派生类仍然还是一个抽象类。4)在抽象类中也可以定义普通成员函数或虚函数,虽然不能为抽象类声明对象,但仍然可以通过派生类对象来调用这些不是纯虚函数的函数。5)不允许从具体类派生出抽象类。
程序示例:在这个程序中,建立两种类型的表,队列和栈。虽然两个表完全不同,但他们可以用同一个接口访问。
1 #include<iostream.h> 2 3 #include<stdlib.h> 4 5 #include<ctype.h> 6 7 Class list 8 9 { 10 11 Public: 12 13 List *head; 14 15 List *tail; 16 17 List *next; 18 19 Int num; 20 21 List() 22 23 { 24 25 Head=tail=next=NULL; 26 27 } 28 29 Virtual void store(int i)=0; 30 31 Virtual void retrieve()=0; 32 33 }; 34 35 Class queue:public list 36 37 { 38 39 Public: 40 41 Void store(int i); 42 43 Int retrieve(); 44 45 }; 46 47 48 49 Void queue::store(int i) 50 51 { 52 53 List *item; 54 55 Item=new queue; 56 57 If(!item) 58 59 { 60 61 Cout<<”Allocation error”<<endl; 62 63 Exit(1); 64 65 } 66 67 Item->num-i; 68 69 If(tail)tail->next=item; 70 71 Tail=item; 72 73 Item->next=NULL; 74 75 If(!head) 76 77 Head=tail; 78 79 } 80 81 82 83 Int queue::retrieve() 84 85 { 86 87 Int i; 88 89 List *p; 90 91 If(!head) 92 93 { 94 95 Cout<<”list empty”<<endl; 96 97 Return 0; 98 99 }100 101 I=head->num;102 103 P=head;104 105 Head=head->next;106 107 Delete p;108 109 Return i;110 111 }112 113 114 115 Class stack:public list116 117 {118 119 Public:120 121 Void store(int i);122 123 Int retrieve();124 125 };126 127 Void stack::store(int i)128 129 {130 131 List *item;132 133 Item=new stack;134 135 If(!item)136 137 {138 139 Cout<<”Allocation error”<<endl;140 141 Exit(1);142 143 }144 145 Item->num=i;146 147 If(head)item->next=head;148 149 Head=item;150 151 If(!tail)152 153 tail=head;154 155 }156 157 158 159 Int stack::retrieve()160 161 {162 163 Int i;164 165 List *p;166 167 If(!head)168 169 {170 171 Cout<<”list empty”<<endl;172 173 Return 0;174 175 }176 177 I=head->num;178 179 P=head;180 181 Head=head->next;182 183 Delete p;184 185 Return i;186 187 }188 189 190 191 Main()192 193 {194 195 List *p;196 197 Queue q_ob;198 199 P=&q_ob;200 201 P->store(1);202 203 P->store(2);204 205 P->store(3);206 207 Cout<<”queue:”;208 209 Cout<<p->retrieve();210 211 Cout<<p->retrieve();212 213 Cout<<p->retrieve();214 215 Cout<<endl;216 217 Stack s_ob;218 219 P=&s_ob;220 221 P->store(1);222 223 P->store(2);224 225 P->store(3);226 227 Cout<<”stack:”;228 229 Cout<<p->retrieve();230 231 Cout<<p->retrieve();232 233 Cout<<p->retrieve();234 235 Cout<<endl;236 237 Return 0;238 239 }
运行结果:
Queue:123
Stack:321
- OOP之多态 【C#】
- objective-c之多态
- objective-c之多态
- 【C#】面向对象之多态
- C#——面向对象之多态
- Linux C之多线程
- Objective-c 特性之多态、动态类型和动态绑定
- Objective-c 特性之多态、动态类型和动态绑定
- Objective-c 特性之多态、动态类型和动态绑定
- C+学习之多态篇(虚函数)
- linux c sockset之多播
- linux c sockset之多播
- java之多态,
- 面向对象之多态
- 面向对象之多态
- c++规范之多态
- C++学习之多态
- 面向对象之多态
- C++之面向程序设计浅析
- 我不是会学会玩
- HDU356 Eight II(康拓展开+预处理)
- PowerShell常用的轉義符、比較符、邏輯操作符
- Python多线程编程
- C++之多态
- mysql存储过程详解
- Linux下SSH远程连接断开后让程序继续运行解决办法
- Python中多线程thread与threading的实现方法
- leetcode_119_Pascal's Triangle II
- java5读写锁技术的妙用(十二)
- Java中泛型小总结
- sqlite+php+ajax 即时聊天系统(ajax 长连接)一
- OC之开篇