迷思 2018-01-09
多态性:在程序多次执行时,某一确定位置的函数调用执行了不同的函数体。
虚函数
虚函数的定义
1.在成员函数(非静态、非构造函数)原型前加上关键字virtual
2.类的虚函数通过继承向下传递,在派生类中既可以直接继承也可以重定义,重定义时函数原型前可以省略virtual,也可以改变访问模式(不提倡),但必须和原来的虚函数具有相同的返回值类型和参数表
虚函数的调用
用对象指针或对象引用对虚函数的调用、成员函数(构造函数和析构函数除外)的函数体中对虚函数的调用将实行动态绑定,其它对虚函数的调用(如对象名加成员选择运算符、虚函数的调用前加类名和作用域运算符)实行静态绑定
示例
#include <iostream.h>
class A
{public:
virtual void f( )
{cout<<"A::f( ) called"<<endl;}
};
class B:public A
{public:
B( ){f( );} //静态绑定
void g( ){f( ); //动态绑定
A::f( ); //静态绑定
}
};
class C:public B
{public:
void f( )
{cout<<"C::f( ) called"<<endl;}
};
main( )
{C c;
c.g( );
return 0;
}
抽象基类和纯虚函数
实现多态性的前提:
1.需要有共同的基类
2.需要在基类中定义共同的接口
3.接口要定义为虚函数
如果基类的接口没办法实现怎么办?
解决方法:
1.不实现这些接口:纯虚函数
2.包含纯虚函数的类:抽象基类
纯虚函数
1.没有函数体的“初始化为0”的函数
//纯虚函数
virtual double area() const = 0;
2.纯虚函数不需要实现,不能被执行
3.通过定义、重定义或继承获得
抽象类和具体类
1.包含纯虚函数(且未对其重定义)的类不能实例化对象,是抽象类
2.如果一个类不是抽象类,则是具体类。
3.抽象类存在的意义是作为其它类的基类,也叫抽象基类
定义或继承获得纯虚函数示例
#include <iostream.h>
class A
{public:
virtual void f( )=0; //纯虚函数定义
};
class B:public A
{public:
B( ){f( );} //静态绑定,错
void g( ){f( ); //动态绑定
A::f( ); //静态绑定,错
}
}; // 类B继承了类A的纯虚函数f,且没有重定义
class C:public B
{public:
void f( )
{cout<<"C::f( ) called"<<endl;}
};
// 类C继承了类A的纯虚函数f,但对f作了重定义
main( )
{C c;
c.g( );
return 0;
}
通过重定义获得纯虚函数示例
#include <iostream.h>
class A
{public:
virtual void f( )
{cout<<"A::f( ) called"<<endl;}
};
class B:public A
{public:
virtual void f( )=0;
//把虚函数f重定义为纯虚函数,virtual可省略
void g( ){f( );}
};
class C:public B
{public:
void f( )
{cout<<"C::f( ) called"<<endl;}
};
// 类C继承了类A的虚函数f和类B的纯虚函数f,
// 但对f作了重定义
main( )
{C c;
c.g( );
return 0;
}
虚析构函数
1.构造函数的执行顺序:从上到下
2.析构函数的执行顺序:从下到上
3.创建对象时要执行正确的构造函数
4.撤销对象时要执行正确的析构函数
动态对象的创建
new ClassName(…);
ClassName指明了要调用的构造函数
动态对象的撤销
delete 基类指针;
如果基类指针指向的是派生类的对象呢?
解决方案:把析构函数定义为虚函数
对于 delete 基类指针; //该类的析构函数为虚函数
程序会根据基类指针指向的对象的类型确定要调用的析构函数
基类的析构函数为虚函数,所有派生类的析构函数都是虚函数
例子一:虚函数与多态性
//文件base.h,定义基类
#if !defined __BASE__H__
#define __BASE__H__
#include <iostream.h>
class Base
{public:
virtual void show( )
{cout<<"I am Base's object!\n";
}
};
#endif
//文件derived.h,定义类Derived
#if !defined __DERIVED__H__
#define __DERIVED__H__
#include "base.h"
class Derived :public Base
{public:
void show()
{cout<<"I am Derived's object!\n";
}
};
#endif
//文件main.cpp,函数调用的动态绑定
#include "derived.h"
main()
{Base *bPtr, bObj;
Derived dObj;
bPtr= &bObj; //基类指针指向基类对象
bPtr->show(); //用指针调用虚函数,动态绑定
bPtr= &dObj; //基类指针指向派生类对象
bPtr->show(); //用指针调用虚函数,动态绑定
return 0;
}
或者
//修改文件main.cpp,用对象引用调用虚函数
#include "derived.h"
main()
{Derived dObj;
Base bObj, &cObj = dObj;
bObj.show(); //用对象调用虚函数,静态绑定
cObj.show();//用对象引用调用虚函数,动态绑定
return 0;
}
例子二:多态性的应用实例
#include <iostream.h>
class shape
{public:
virtual double area(){return 0.0; }
virtual ~shape(){ }
};
double total(shape *s[],int n)
{double sum=0;
for(int i=0;i<n;i++)
sum+=s[i]->area(); //动态绑定
return sum;
}
class triangle: public shape
{protected:
double H,W;
public:
triangle(double h, double w){H=h;W=w;}
double area(){return H*W*0.5;}
};
class rectangle: public triangle
{public:
rectangle(double h, double w)
:triangle(h,w){ }
virtual double area();
};
double rectangle::area(){return H*W;}
class screen
{private:
shape *s[100];
int n;
public:
screen(){n=0;}
void addshapetoscreen(shape *sp)
{if(n<100)n++;
s[n-1]=sp;
}
double total()
{double sum=0;
for(int i=0;i<n;i++)
sum+=s[i]->area();
return sum;
}
};
main()
{shape *s[100];
s[0]=new triangle(2.2,3.3);
s[1]=new rectangle(2.0,4.0);
cout<< total(s,2) << endl;
screen ss;
ss.addshapetoscreen(s[0]);
ss.addshapetoscreen(s[1]);
cout<<ss.total();
for (int i=0;i<2;i++)
delete s[i];
return 0;
}
//增加新的图形不需要修改total函数和screen类
//增加相关图形类
class circle: public shape
{private:
double radius;
public:
circle(double r)
{radius=r;}
double area()
{return radius*radius*3.14159;}
};
//修改主函数
main()
{shape *s[4];
s[0]=new triangle(2.2,3.3);
s[1]=new rectangle(2.0,4.0);
s[2]=new circle(5.0);
s[3]=new circle(8.0);
cout<< total(s,4) <<endl;
screen ss;
ss.addshapetoscreen(s[0]);
ss.addshapetoscreen(s[3]);
cout<<ss.total();
for (int i=0;i<4;i++)
delete s[i];
return 0;
}
例子三:抽象基类的例子
//文件shape.h,定义抽象基类Shape
#if !defined __SHAPE__H__
#define __SHAPE__H__
#include <iostream.h>
class Shape
{public:
virtual double area() const = 0;
virtual void show() const = 0;
};
#endif
//文件circle.h,定义派生类Circle
#if !defined __CIRCLE__H__
#define __CIRCLE__H__
#include "shape.h"
#define PI 3.1416
class Circle :public Shape
{public:
Circle(double = 0.0,
double = 0.0, double = 1.0);
double area() const;
void show() const;
private:
double x,y;
double r;
};
#endif
//文件circle.cpp,实现类Circle
#include "circle.h"
Circle::Circle(double a,
double b, double c)
{ x = a;
y = b;
r = c;
}
double Circle::area() const
{return PI*r*r;
}
void Circle::show() const
{cout<<"I am a Circle: ";
}
// Circle是具体类
//文件rectangle.h,定义派生类Rectangle
#if !defined __RECTANGLE__H__
#define __RECTANGLE__H__
#include "shape.h"
class Rectangle :public Shape
{public:
Rectangle(double = 1.0, double = 1.0);
double area() const;
void show() const;
private:
double length;
double width;
};
#endif
//文件rectangle.cpp,实现类Rectangle
#include "rectangle.h"
Rectangle::Rectangle(double a, double b)
{ length = a;
width = b;
}
double Rectangle::area() const
{
return length*width;
}
void Rectangle::show() const
{
cout<<" I am a Rectangle: ";
} // Rectangle是具体类
//文件main.cpp,测试类Shape的虚函数
#include "circle.h"
#include "rectangle.h"
void callArea(Shape &obj)
{obj.show(); //动态绑定
cout<<"area = "<<obj.area()<<endl;
} // obj.area()动态绑定
main()
{Circle cir(0.0, 0.0, 2.5);
Rectangle rec(2.4, 5.3);
//能用Shape类声明对象吗?
callArea(cir);
callArea(rec);
return 0;
}
例子四:虚析构函数的例子
//文件employee.h,定义基类Employee
#include <iostream.h>
#if !defined __EMPLOYEE__H__
#define __EMPLOYEE__H__
class Employee
{public:
Employee()
{cout<<"Employee begin!"<<endl;
}
virtual ~Employee()
{cout<<"Employee end!"<<endl;
}
};
#endif
//文件programmer.h,定义派生类Programmer
#include <iostream.h>
#include <string.h>
#include "employee.h"
class Programmer: public Employee
{public:
Programmer(char *str)
{cout<<"Programmer begin!"<<endl;
name = new char[strlen(str)+1];
strcpy(name, str);
}
~Programmer()
{delete [] name;
cout<<"Programmer end!"<<endl;
}
private:
char *name;
};
//文件accountant.h,定义派生类Accountant
#include <iostream.h>
#include "employee.h"
class Accountant: public Employee
{public:
Accountant(int n)
{cout<<"Accountant begin!"<<endl;
age = n;
}
~Accountant()
{cout<<"Accountant end!"<<endl;
}
private:
int age;
};
//文件main.cpp
#include "accountant.h"
#include "programmer.h"
const int MAX = 100;
main()
{ int no;
//声明储存雇员信息的数组
Employee *ptr[MAX], *tptr;
int ENum = 0;
char name[100];
int age;
for (int i=0; i<MAX; i++)
ptr[i] = NULL;
//输入雇员信息
cout<<"Input employees' info:"<<endl;
cout<<"1 --- Programmer"<<endl
<<"2 --- Accountant"<<endl
<<"0 --- exit"<<endl;
cin>>no;
while (no)
{switch (no)
{case 1:
cout<<"Please input name:";
cin>>name;
//创建程序员对象
tptr = new Programmer(name);
ptr[ENum++] = tptr;
break;
case 2:
cout<<"Please input his or her age:";
cin>>age;
//创建会计对象
tptr = new Accountant(age);
ptr[ENum++] = tptr;
break;
default:
break;
}
cout<<"Input another employee's info:“
<<endl;
cout<<"1 --- Programmer"<<endl
<<"2 ---Accountant"<<endl
<<"0 --- exit"<<endl;
cin>>no; }
//撤销所有雇员对象
for (i=0; i<ENum; i++)
{
delete ptr[i];
}
return 0;
}
继承对象模型在 C++ 编译器的内部类可以理解为结构体子类是由父类成员叠加子类新成员得到的class Dervied : public Demo. << "mk = " << mk << endl;c