第8章多态性与虚函数
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
1. 多态性
从实现时机方面讲,多态性可以分为: 静态多态性 动态多态性
静态多态性 : 指可在编译期间确定的多态性。 静态多态性: 函数重载 运算符重载
动态多态性: 指在程序在运行过程中,才能确定的多 态性。
静态多态性:
1)函数重载:几个函数具有相同的名字,但函数参数 的个数或类型不同。
重载的函数可以是: 一般函数 类中的成员函数、构造函数
private: double real,imag;
}; complex operator+( const complex &a,const complex &b) { return complex(a.real+b.real,a.imag+b.imag);} void complex::display()
运算符重载:
用类的成员函数的格式如下: class 类名 {
...... 返回类型 operator 运算符(形参表); ...... };
例:利用成员函数实现两个复数相加运算。
#include <iostream.h> class complex{
public: complex(double r=0,double i=0){real=r;imag=i;} complex operator+(const complex &a); void display();
第8章 多态性与虚函数
本章内容
多态性概述 运算符重载 虚函数及动态多态性
1. 多态性概述
多态性是面向对象程序设计的一个重要特征。
• 多态性:是指发出同样的消息被不同类型的对象
接收时而导致不同的行为。
•多态是指类中具有相似功能的不同函数使用同一
个名称。当调用这个相同名称的函数时,可根据需 要完成不同的功能.
#include <iostream.h>
const double PI=3.14159;
class Point{
//定义基类
public:
Point(double i,double j){x=i;y=j;}
double Area(){return 0.0;}
pຫໍສະໝຸດ Baiduivate:
double x,y;
//点坐标
private:
double x,y;
//点坐标
};
class Line: public Point{
double x1,y1;
//增加终点坐标成员
public:
Line(double i1,double j1,double i2,double j2):Point(i1,j1)
{ x1=i2; y1=j2; }
例:利用友元函数实现两个复数相加运算。
#include <iostream.h> class complex{
public: complex(double r=0,double i=0){real=r;imag=i;} friend complex operator+(const complex &a,const complex & void display();
#include <iostream.h> #include <string.h>
成员函数重载例题:
class string
{ public: string(char *pa);
void print( ) { cout<<pstr<<endl; }
void print(char *str) { cout<<str<<endl; }
private: char *pstr;
};
string::string(char *pa)
{ pstr=new char[strlen(pa)+1]; strcpy(pstr, pa);
}
void main( )
{ string s1(“programming”);
s1.print( ); s1.print(“C++”);
#include <iostream.h>
class count
{ int a,b;
public:count(int i,int j){ a=i; b=j; }
void show( ){ cout<<a<<“ “<<b<<endl;}
void operator++( );
void operator - -( );
};
class Line:public Point{
double x1,y1;
//增加终点坐标成员
public:
Line(double i1,double j1,double i2,double j2):Point(i1,j1)
{ x1=i2; y1=j2;}
double Area( ) { return 0.0; }
}
11 21 29 39 11 21
运算符重载:
小结:
对单目运算符,当以成员函数形式重载运算 符时没有参数,以友元函数形式重载运算符 时有一个参数;
对双目运算符,当以成员函数形式重载运算 符时有一个参数;以友元函数形式重载运算 符时有两个参数;
运算符重载:
两种重载形式的比较:
对于单目运算符,常常选择用成员函数;对于 运算符“=、( )、[ ]、->”只能选择用成员函数; 对于复合赋值运算符“+=、-=、/=、*=”等常 常选择用成员函数。
虚函数:
虚函数是类中的成员函数。 虚函数的一般格式如下: virtual 类型名 函数名(形参表) { 函数体 }
虚函数说明:
•一个函数被说明或定义为虚函数后,表明它
在派生类中可能有多种不同的实现,即重新定 义。
•在派生类中重新定义时,其函数原型,包括
返回类型、函数名、参数个数和类型以及各参 数顺序,都必须与基类中的原型完全相同。否 则,将处理为静态联编。
void main(){ complex c1(3,4), c2(5,-10), c3;
程序说明: 成员函数
complex operator+(const complex &a) 用于定义“+”运算符重载 复数类对象相加: c1+c2,
相当于 : c1.operator+ (c2)
运算符重载:
上例函数fun()的形参也可以是如下形式:
void fun(Point &p)
{ cout<<p.Area()<<endl; }
main( )函数也要相应改成如下形式:
void main( ){ Line lin(1,3,4,5); //定义线对象 fun(lin); Circle cir(10,3,6); //定义圆对象 fun(cir); Rectangle rec(7,8,2,5); //定义矩形对象 fun(rec); }
例题:构造函数重载: #include <iostream.h> class classA { public: classA( ){a1=0;a2=0;cout<<”default\n”; }
classA(int i,int j); void print( ){ cout<<a1<<”,”<<a2<<endl; } ~A( ) { cout<<”destructure\n”; } private: int a1,a2; }; classA::classA(int i,int j) { a1=i; a2=j; cout<<”constructure\n”; } void main() { classA ob1,ob2(12,8); ob1.print( ); ob2.print(); }
};
void count::operator++( ){ a++; b++; }
void count::operator- - ( ){ a- -; b- -; }
void main( )
运行结果
{ count ob1(10,20); ob1++; ob1.show( ); count ob2(30,40); ob2- -; ob2.show( ); ob2=ob1; ob2.show( );
的运算符;
重载运算符时不能改变原运算符操作数的个数、原有
运算符的优先级和结合性,也不能改变原运算符对 于内部基本类型对象的含义;
如果重载了某个运算符(如“=”),并不意味着重载了
相关的运算符(如“+=”、“-=”等);
运算符重载:
运算符重载函数的实现: 可以利用: 成员运算符函数 友元运算符函数
学习时注意:不同的实现方法,参数的 个数不同。
{cout<<"("<<real<<", "<<imag<<"i)"<<endl;} void main(){
complex c1(3,4),c2(5,-10),c3; c3=c1+c2; c1.display();cout<<"+";c2.display();cout<<"=";c3.display(); co
virtual double Area(){ return 0.0; } //定义虚函数
};
程序说明:
各派生类中重定义的虚函数仍是虚函数,不 管是否有virtual。
虚函数的调用 在main()中定义指向根基类的指针p可以指
向派生类对象。
在执行过程中,可根据指针p的当前指向而 调用相应类的虚函数,从而实现动态的多态 性。
对于其他运算符,如“+、-、*、/”等常常选 择用友元函数,以适应更多的计算形式。
运算符重载:
使用说明:
例如,对于复数类对象相加来说, 用友元函数 实现时,表达式4.5+c1可以正确计算,将被解释 成operator+(complex(4.5),c1)。
而用成员函数实现时, 表达式4.5+c1将是一个 错误的表达式,因为若将以上加法重载为成员函 数时,表达式4.5+c1将被解释为4.5.operator+(c1), 而4.5是一个基本类型的常数,不能自动转换为复 数类对象。
private: double real,imag;
}; complex complex:: operator+(const complex &a) { return complex(real+a.real,imag+a.imag); }
void complex::display() { cout<<"("<<real<<", "<<imag<<"i)"<<endl; }
3. 虚函数与动态多态
虚函数是一种成员函数,而且是非static的成员函数。
一个函数被说明或定义为虚函数后,说明表示它在派 生类中可能有多种不同的实现。
虚函数只能通过指针或引用所表示的对象来调用。
构造函数不允许为虚函数,但析构函数允许为虚函数, 以便能自动释放由指针或引用所表示的对象。
例:不使用虚函数的静态联编示例。 结果: 0 0 0
}
2. 运算符重载 运算符重载: 将已有的运算符赋予新的含义。
不可重载的运算符
“•”
圆点运算符
“•*” 成员指针选择运算符
“∷” 域分辨运算符
“?:” 条件运算符
“sizeof” 长度运算符
除以上五个运算符外,其余运算符均可重载。
运算符重载:
重载运算符的规则:
只能重载C++中已有的可重载的运算符,不能建立新
};
class Circle:public Point{
虚函数:
基类对象与派生类对象之间的赋值兼容性表现在:
把派生类对象赋给基类对象
A a1; B b1; a1=b1;
用派生类对象向基类对象的引用赋值或初始化
A a1; B b1; A &r1=a1; r1=b1; A &r2=a2;
把派生类对象的地址赋给基类对象的指针变量
程序说明:
友员函数
friend complex operator+( const complex &a,const complex &b)
复数类对象相加:c1+c2, 相当于:operator+(c1,c2)
注意:用友元函数 operator+( ) 必须有两个参数。
单目运算符重载例题: 重载++、- -、=,同时实现2个变量的加1、减1。
A *p;B b1; p=&b1;
例:动态联编示例。
#include <iostream.h>
const double PI=3.14159;
class Point{
//定义根基类
public:
Point(double i,double j){ x=i; y=j; }
virtual double Area(){ return 0.0; } //定义虚函数
用类的友元函数的格式如下。 class 类名 {
...... friend 返回类型 operator运算符(形参表); ...... };
运算符重载:
由于友元函数被调用时没有隐含指向当前对 象的this指针作实参,所以,一个一元运算符重 载为类的友元函数时,其参数个数为1,一个二 元运算符重载为类的成员函数时,其参数个数 必须为2。