栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++之多态

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++之多态

目录

多态

静态联编

普通成员函数重载可表达为两种形式:

1. 在一个类说明中重载

2. 基类的成员函数在派生类重载。有 3 种编译区分方法:

基类指针和派生类指针与基类对象和派生类对象4种可能匹配:

 实现动态联编方式的前提

虚函数和动态联编


多态 Ø 多态性( Polymorphism )是指一个名字,多种语义;或界面相同,多种实现。 Ø 重载函数是多态性的一种简单形式。 Ø 虚函数允许函数调用与函数体的联系在运行时才进行,称为动态联编。

多态性的实现和联编这一概念有关。所谓联编(Binding,绑定)就是把函数名与函数体的程序代码连接(联系)在一起的过程。

联编分成两大类:静态联编和动态联编。

静态联编优点:调用速度快,效率高,但缺乏灵活性;动态联编优点:运行效率低,但增强了程序灵活性。

C++为了兼容C语言仍然是编译型的,采用静态联编。为了实现多态性,利用虚函数机制,可部分地采用动态联编。

多态从实现的角度来讲可以划分为两类:编译时的多态和运行时的多态。

编译时的多态是通过静态联编来实现的。静态联编就是在编译阶段完成的联编。编译时多态性主要是通过函数重载和运算符重载实现的。

运行时的多态是用动态联编实现的。动态联编是运行阶段完成的联编。运行时多态性主要是通过虚函数来实现的。

静态联编 Ø 联编是指一个程序模块、代码之间互相关联的过程。 Ø 静态联编,是程序的匹配、连接在编译阶段实现,也称为早期匹配。 Ø 重载函数使用静态联编。 Ø 动态联编是指程序联编推迟到运行时进行,所以又称为晚期联编。 Ø switch 语句和 if 语句是动态联编的例子。

普通成员函数重载可表达为两种形式:

1. 在一个类说明中重载

例如:  void Show ( int , char ) ;

             void Show ( char * , float ) ;

2. 基类的成员函数在派生类重载。有 3 种编译区分方法:

(1)根据参数的特征加以区分

例如:  void Show ( int , char );       与

             void Show ( char * , float ); 不是同一函数,编译能够区分

(2)使用“ :: ”加以区分

例如:  A :: Show ( );

             有别于  B :: Show ( );

(3)根据类对象加以区分

例如:  Aobj . Show ( )  调用  A :: Show ( )

             Bobj . Show ( )  调用  B :: Show ( )

基类指针和派生类指针与基类对象和派生类对象4种可能匹配:

Ø 直接用基类指针引用基类对象;

Ø 直接用派生类指针引用派生类对象;

Ø 用基类指针引用一个派生类对象;

Ø 用派生类指针引用一个基类对象。

9.2.1  基类指针引用派生类对象

例如: 

A    * p ;  // 指向类型 A 的对象的指针

A    A_obj ;  // 类型 A 的对象

B    B_obj ;  // 类型 B 的对象

p = & A_obj ;  // p 指向类型 A  的对象

p = & B_obj ;  // p 指向类型 B  的对象,它是 A 的派生类

  利用 p,可以通过 B_obj 访问所有从 A 类继承的元素 ,

  但不能用 p访问 B 类自定义的元素 (除非用了显式类型转换)

#include
#include
using namespace std ;
class  A_class
{
char name[20] ;
public:
    void  put_name( char * s ) { strcpy_s( name, s ) ; 
    void  show_name() { cout << name << "n" ; }
};
class  B_class  : public  A_class
{      
char phone_num[ 20 ] ;
public :    
   void  put_phone( char * num )  { strcpy_s ( phone_num , num ) ; }
   void  show_phone()  { cout << phone_num << "n" ; }
};
int main()
{ 
   A_class  * A_p ;
   A_class  A_obj ;
   B_class   B_obj ;  
   A_p = & A_obj ;     
   A_p -> put_name( "Wang xiao hua" ) ;
   A_p -> show_name() ;  
   A_p = & B_obj ;
   A_p -> put_name( "Chen ming" ) ;
   A_p -> show_name() ; 
   B_obj.put_phone ( "5555_12345678" );
   ((B_class *) A_p ) -> show_phone() ;
}

  派生类指针只有经过强制类型转换之后,才能引用基类对象

#include
using namespace std ;
class Date{
public:
    Date( int y, int m, int d )   { SetDate( y, m, d ); }
    void SetDate( int y, int m, int d ) { year = y ; month = m ; day = d ; }
    void Print() { cout << year << '/' << month << '/' << day << "; " ; }
protected :
    int year,month,day;
} ;
class DateTime : public Date
{ 
public :
       DateTime( int y, int m, int d, int h, int mi, int s ):Date( y, m, d )
            { SetTime( h, mi, s ); }
       void SetTime( int h, int mi, int s )
            { hours = h;  minutes = mi;  seconds = s; }
       void Print()
         { ( ( Date * ) this ) -> Print();	
             cout << hours << ':' << minutes << ':' << seconds << 'n' ; 
         }
private:
    int hours , minutes , seconds ;	  
};
int main()
{
   DateTime dt( 2009, 1, 1, 12, 30, 0 ) ;
   dt.Print() ;
}

 实现动态联编方式的前提

●先要声明虚函数

●类之间满足赋值兼容规则

●通过指针与引用来调用虚函数。

虚函数和动态联编 Ø  冠以关键字 virtual 的成员函数称为虚函数 Ø 实现运行时多态的关键首先是要说明虚函数,另外,必须用

  基类指针调用派生类的不同实现版本

 基类指针虽然获取派生类对象地址,却只能访问派生类从基类继承的成员

#include
using namespace std ;
class  Base
{ 
public :
    Base(char xx)  { x = xx; }
    void who()  { cout << "Base class: " << x << "n" ; }
protected:
    char x;
} ;
class  First_d : public  Base
{ 
public :
     First_d(char xx, char yy):Base(xx)  { y = yy; }
     void who()  { cout << "First derived class: "<< x << ", " << y << "n" ; }
protected:
     char y;
} ;
class  Second_d : public  First_d
{
public :
     Second_d( char xx, char yy, char zz ) : First_d( xx, yy ) { z = zz; } 
     void who()  { cout << "Second derived class: "<< x << ", " << y << ", " << z << "n" ; }
protected:
    char z;
} ;
int main()
{ 
Base  B_obj( 'A' ) ;
First_d F_obj( 'T', 'O' ) ;
Second_d S_obj( 'E', 'N', 'D' ) ;
Base  * p;
p = & B_obj;
p -> who();
p = &F_obj;
p -> who();
p = &S_obj;
p -> who();
F_obj.who();
((Second_d *)p)->who() ;
}

 

通过基类指针只能访问从基类继承的成员!!!

#include
using namespace std ;
class  Base
{
public :
    Base(char xx)  { x = xx; }
    virtual void who()  { cout << "Base class: " << x << "n" ; }    //基类定义虚函数
protected:
    char x;
} ;
class  First_d : public  Base
{ 
public :
     First_d(char xx, char yy):Base(xx)  { y = yy; }
     void who()  { cout << "First derived class: "<< x << ", " << y << "n" ; }
protected:
     char y;
} ;
class  Second_d : public  First_d
{ 
public :
     Second_d( char xx, char yy, char zz ) : First_d( xx, yy ) { z = zz; } 
     void who()  { cout<<"Second derived class: "< who() ;
p = &F_obj ;
p -> who() ;
p = &S_obj ;
p -> who() ;
}

 如此一来,基类指针便可以根据不同的类,实现相同函数对应不同类的不同的功能!!!

注意:

  1. 一个虚函数,在派生类层界面相同的重载函数都保持虚特性
  2. 虚函数必须是类的成员函数
  3. 不能将友元说明为虚函数,但虚函数可以是另一个类的友元
  4. 析构函数可以是虚函数,但构造函数不能是虚函数
  5. 在派生类中重载基类的虚函数要求函数名、返回类型、参数个数、参数类型和顺序完全相同
  6. 如果仅仅返回类型不同,C++认为是错误重载
  7. 如果函数原型不同,仅函数名相同,丢失虚特性

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/982581.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号