C++课上ppt5复习 Polymorphism

Two types of polymorphism

Compile-time polymorphism(编译时多态性)association done in compile time, including

1function overloading

2operator overloading

Run-time polymorphism(运行时多态性)association done during run time. Implemented by dynamic biding( inheritance plus virtual function).

binding(绑定)

Binding is the process of associating a function call and a function definition.


Two types of biding

Static bidingEarly biding

Done during compile-time

Applied to non-virtual function.

Dynamic bidinglate biding

Done during run-time.

Applied to virtual function.


virtual function(虚函数)

A virtual function is a member function with reserved word virtual of a class.

“一旦为虚,永远为虚”:The virtual function of a base will always be virtual in its derived classes.

主要作用:与继承相结合以实现运行时多态性。在公有继承层次中的一个或多个派生类中对虚函数进行重定义,

 然后通过指向基类的指针(或引用)调用虚函数来实现实现运行时多态性。


Slicing(切割问题)

用值传递的方式把派生类的对象传递给父类对象时,仅传递它们相同的数据成员,派生类比父类多出来的数据成员被切割掉。

使用引用形参,可避免切割问题,因为传递的是实参的内存地址。


Dynamic Binding 

Is the run-time determination of which function to call for a particular object of a descendant class 

based on the type of the argument. 

Declaring a member function to be virtual instructs the compiler to generate code that guarantees


1.MemberFunc不是虚函数,

形参类型决定调用哪个函数(静态绑定)

2.MemberFunc是虚函数,

实参类型决定调用哪个函数(动态绑定)


静态绑定

void main( )
{	
    BASE b_obj;		
    FIRST_D f_obj;		
    SECOND_D s_obj;
    BASE *p;	 // 定义指向基类的指针
    p= &b_obj;	p->who();
    p= &f_obj;	p->who();     // 根据赋值兼容性规则
    p= &s_obj;	p->who();     // 基类指针可指向派生类对象
}
输出结果:	
BASE
BASE		
BASE

不管p指向什么对象,通过p三次调用的都是基类的who函数。

原因:调用普通成员函数采用静态绑定方式。通过指针(或引用)调用普通成员函数,仅仅与指针(或引用)的基类型有关,

而与该指针当前所指向(或引用当前所关联)的对象无关。


动态绑定

将基类BASE修改为:

class BASE {
public: 	 
      virtual void who( ) 
     {   cout<<“BASE\n”;  }
};
输出结果:	
BASE
The First Derivation
The Second Derivation 

则函数调用p->who()进行动态绑定:实际调用哪个who函数依赖于运行时p所指向的对象

动态绑定的另一实现方式:使用引用形参

void print_identity( BASE& me )
{	
      me.who();    //通过基类引用调用虚函数
}
void main( )
{	
      BASE b_obj;		
      FIRST_D f_obj;		
      SECOND_D s_obj;
      print_identity(b_obj);			
      print_identity(f_obj);
      print_identity(s_obj);
}
输出结果:
BASE
The First Derivation
The Second Derivation


关于虚函数的说明

用虚函数实现动态绑定的关键:必须用基类指针(或基类引用)来访问虚函数。

若一函数是类中的虚函数,则称该函数具有虚特性。

在派生类中重定义从基类中继承过来的虚函数(函数原型保持不变),该重定义的函数在该派生类中仍是虚函数。

函数重载,虚特性丢失。

当一个派生类没有重新定义虚函数时,则使用其基类定义的虚函数版本。

class BASE {
public: 	
	virtual void f1( ) { cout<<"BASE::f1()"<<endl; }
	virtual void f2( ) { cout<<"BASE::f2()"<<endl;  }
	virtual void f3( ) { cout<<"BASE::f3()"<<endl;  }
	void f ( ) { cout<<"BASE::f()"<<endl;  }
};

class DERIVED:public BASE {
public: 
      void f1( ) { cout<<"DERIVED::f1()"<<endl;  }
      //虚函数的重定义,f1在该类中还是虚函数
      void f2( int ) { cout<<"DERIVED::f2()"<<endl; }	
      //f2是函数重载,虚特性丢失
      void f ( ) { cout<<"DERIVED::f()"<<endl; }  // 普通函数的重定义
};

Pure virtual function(纯虚函数)

a virtual function declared but without definition within a base classEach derived class of this base 

 must redefine and implement this function.

virtual 返回值类型 函数名(形参表) =0

一般用于抽象类Abstract class

继承的派生类中,该函数还是带有virtual

class FIGURE {
public:
	void set_size(double x, double y = 0);
	virtual double get_area() = 0;	// get_area()被声明为纯虚函数
protected:
	double x_size, y_size;
};
class TRIANGLE: public FIGURE {
public:
	virtual double get_area();
};
class RECTANGLE: public FIGURE {
public:
	virtual double get_area();	
};

Template

Generic programming(泛型编程)

Function template(函数模板)

Class template(类模板)

Non-type parameters(非类型模板形参)

Generic programming:programming independent of any particular data types by which data(objects) of different types 

 can be manipulated by the same codes.

Instantiation(实例化) is the process in which different instance codes are created from the same generic code by the compiler.

In C++, template is used for generic programming.


Function template

template <typename T>
void swap( T& v1, T& v2)
{
       T temp;
       temp = v1;
       v1 = v2;
       v2 = temp;
}

Class template

template <class T>
void swap( T& v1, T& v2)
{
       T temp;
       temp = v1;
       v1 = v2;
       v2 = temp;
}

调用函数模板的实际过程:

1.模板实参推断template argument deduction):编译器根据函数调用中所给出的实参的类型,确定相应的模板实参。

2.函数模板的实例化instantiation):模板实参确定之后,编译器就使用模板实参代替相应的模板形参,

 产生并编译函数模板的一个特定版本(称为函数模板的一个实例(instance))(注意:此过程中不进行常规隐式类型转换)。

对函数模板进行重载:定义名字相同而函数形参表不同的函数模板,或者定义与函数模板同名的非模板函数,在其函数体中完成不同的行为。


如何确定调用哪个函数?

静态绑定:编译时将一个函数调用关联到特定的函数体代码的过程。

函数调用的静态绑定规则 

1如果某一同名非模板函数的形参类型正好与函数调用的实参类型匹配(完全一致),则调用该函数。否则,进入第2步。

2如果能从同名的函数模板实例化一个函数实例,而该函数实例的形参类型正好与函数调用的实参类型匹配(完全一致),

 则调用该函数实例。否则,进入第3步。

3对函数调用的实参作隐式类型转换后与非模板函数再次进行匹配,若能找到匹配的函数则调用该函数。否则,进入第4步。

4提示编译错误。


类模板

定义形式:

template < 模板形参表 >

class 类模板名

{ 类成员声明  };

其中,模板形参表形式如下:

typename 模板形参1, typename 模板形参2, 

在类模板以外定义其成员函数,则函数首部形式如下:

template <模板形参表>

返回值类型 类模板名<模板形参名列表>::函数名函数形参表 )


类模板的使用

类模板的实例化

类模板是一个通用类模型,而不是具体类,不能用于创建对象,只有经过实例化后才得到具体类,才能用于创建对象。

实例化的一般形式:

               类模板名 模板实参表 

模板实参是一个实际类型。

一个类模板可以实例化为多个不同的具体类。

        Stack<int> stack_int

        Stack<double> stack_double;

        Stack<string> stack_string;


两种模板编译模式

包含编译模式(inclusion compilation model

要求:在函数模板或类模板成员函数的调用点,相应函数的定义对编译器必须是可见的。 

实现方式:在头文件中用#include包含实现文件(也可将模板的实现代码直接放在头文件中)。

分离编译模式(separate compilation model

要求:程序员在实现文件中使用保留字export告诉编译器,需要记住哪些模板定义。

不是所有编译器都支持该模式。

模板的定义和实现都写在.h文件中。属于包含编译模式

类模板声明体放在头文件中,将类模板成员函数的定义和类的静态数据成员的定义放在实现文件中,属于包含编译模式。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值