c++语法笔记(下)


多态性与虚函数
多态性(函数重载,运算符重载就是多态性现象)
多态性 :向不同对象发送同一个消息,不同对象在接收时会产生不同的行为。(每个对象用自己的方式去响应共同的消息)
多态性又可以分为静态多态性和动态多态性
静态多态性在编译时编译系统就可以判定调用哪个重载运算符(函数)。
#include
using namespace std;
class point {
public:
 point(float a, float b) {             //构造函数 
  x = a; y = b;
 }
 friend ostream & operator <<(ostream &, point &);        //运算符重载 
protected:
 float x, y;
};
std::ostream &operator<<(std::ostream &output, point &p) {        //运算符重载的定义 
 output << "(" << p.x << "," << p.y << ")" << endl;
 return output;
}
class circle :public point {
public:
 circle(float a, float b, float c) :point(a, b), radius(c) {}      //构造函数
 friend ostream &operator <<(ostream &, circle &); 
 
protected:
 float radius;
};
 ostream &operator <<(ostream &output, circle &c) {
  output << "(" << c.x << "," << c.y << ")," << "radius=" << c.radius << endl;
  return output;
 }
int main() {
 point a(2.3, 4.6);
 cout << "the point is:" << a << endl;
 circle m(0, 0, 8);
 cout << "the circle is" << m << endl;
}

利用虚函数实现动态多态性
(所谓虚函数,就是在基类声明函数是虚拟的,并不是实际存在的函数,
  然后在派生类中才正式定义此函数,在程序运行期间,用指针指向某一派生类的对象,这样就能调用指针指向的派生类对象的函数)
#include
using namespace std;
class point {
public:
 point(float a, float b) {             //构造函数 
  x = a; y = b;
 }
 virtual void display();               //虚函数
protected:
 float x, y;
};
void point::display(){
 cout<<"(" << x << "," << y << ")"<<endl;
} 

class circle :public point {
public:
 circle(float a, float b, float c) :point(a, b), radius(c) {}      //构造函数
 void display();
protected:
 float radius;
};
void circle::display(){
 cout<< "(" << x << "," << y << ")," << "radius=" << radius << endl;
}
int main() {
 point a(2.3, 4.6);
 circle m(0, 0, 8);
 point *p1=&a;     //基类指针
 p1=&m;
 p1->display();
 return 0;  
}
输出的结果是:(0,0)radius=8
说明:本来基类指针是用来指向基类对象的,如果把它指向派生类对象,则自动进行指针类型转换,
将派生类的对象的指针先转换为基类指针,这样基类指针指向的就是对象中的基类成分。
虚函数突破了这一限制,基类的display函数声明为虚函数,在声明派生类时被重载,这时派生类的同名函数display就取代了基类的虚函数。
虚函数的使用方法:
1.在基类声明成员函数为虚函数,在类外定义虚函数是不必加virtual
2.一个成员函数被声明为虚函数后,在同一类族中的类就不能在定义一个非virtual的但与该虚函数具有相同参数和函数返回值的同名函数。  
虚析构函数
析构函数的作用是在对象撤销之前做必要的清理现场的工作,当派生类的对象从内存中撤销时一般先调用派生类的析构函数,然后调用基类的析构函数。
但如果使用new运算符建立了临时对象,若基类有析构函数,并且定义了一个指向该基类的指针。
在程序用带指针参数的delet运算符撤销对象时,系统只会执行基类的析构函数,而不执行派生类的析构函数。
如果在基类的析构函数声明为虚析构函数,就可以使实现先调用派生类的析构函数,再调用基类的析构函数。 
#include
using namespace std;
class point {
public:
 point(float x = 0, float y = 0);             //声明构造函数时指定默认参数 
 virtual ~point() {
  cout << "executing point destructor" << endl;
 }
protected:
 float x, y;
};
point::point(float a,float b){                  //在定义构造函数时可以不指定默认参数 
 x=a;
 y=b;
}
class circle :public point {
public:
 circle(float x = 0, float y = 0, float r = 1) ;
 ~circle() {
  cout << "executing circle destructor" << endl;
 }
protected:
 float r;
};
circle::circle(float a,float b,float c){
 x=a;
 y=b;
 r=c;
}
int main() {
 point *p = new circle;
 delete p;
 return 0;
}
纯虚函数
由于派生类的需要,将基类中某一成员函数定义为虚函数(预留一个函数名),具体功能由派生类定义。
声明虚函数的例子:
virtual float area() {return 0;}
为了简化,可以不写函数体
virtual float area()=0; 注意:纯虚函数没有函数体
      最后面“=0”只起形式上的作用,告诉编译系统“这是纯虚函数”
       这是一个声明语句,最后有分号;
抽象类
有时定义一些类,它们专门作为基类去建立派生类,而不用来定义对象,我们称它们为抽象类(抽象基类)。凡是包含纯虚函数的类都是抽象类,
纯虚函数是不能被调用的,包含纯虚函数的类是无法建立对象的。(不过可以定义指向抽象类数据的指针变量,当派生类成为具体类时,
就可以用这种指针指向派生类的对象,通过该指针调用虚函数,实现多态性)
//虚函数与抽象基类的应用
#include
using namespace std;
//声明抽象抽象基类shape 
class shape{                                    
 public:
  virtual float area() const {return 0;}             //虚函数 
  virtual float volume() const {return 0;}
  virtual void shapname() const=0;                 //纯虚函数 
  
}; 
//声明point类 
class point:public shape {
 public:
  point(float x=0,float y=0);         //声明构造函数 
  virtual void shapname() const {cout<<"point";}
 protected:
  float x,y;
}; 
//定义point 
point::point(float a,float b){
 x=a;
 y=b;
}

//声明circle类 
class circle:public point{
 public:
  circle(float x=0,float y=0,float r=0);
  virtual float area() const;
  virtual void shapname() const {cout<<"circle:";}
 protected:
  float radius;
}; 
//定义circle类 
circle::circle(float a,float b,float r):point(a,b),radius (r) {}    //定义构造函数 
    
float circle::area() const {return radius*radius*3.14;}

//声明cylinder类 
class cylinder:public circle{
 public:
  cylinder(float x=0,float y=0,float r=0,float h=0);
  virtual float area() const;
  virtual float volume() const;
  virtual void shapname() const{cout<<"cylinder:";}
 protected:
  float height; 
}; 
//定义cylinder类 
cylinder::cylinder(float a,float b,float r,float h):circle(a,b,r),height(h){}
float cylinder::area() const{
 return 2*circle::area()+2*radius*3.14*height;
}
float cylinder::volume() const{
 return height*circle::area();
}
//main函数 
int main(){
 point point(0,0);
 circle circle(0,0,3);
 cylinder cylinder(2,2,1,1);
 point.shapename;                //静态关联(通过对象名调用虚函数)在编译阶段就可以确定调用的是哪一类的虚函数
 shape *pt;                      //定义基类指针 
 pt=&point;                      //使指针指向point类 
 pt->shapname();                 //用指针建立动态关联 (在编译阶段无法从语句本身确定调用的是哪个类的虚函数)
 cout<<"\n";
 pt=&circle;
 pt->shapname();
 cout<<"area="<area()<<"\n"<<endl;
 
 pt=&cylinder;
 pt->shapname();
 cout<<"area="<area()<<"\n"
 <<"volume="<volume()<<endl;
 return 0;
}