c++学习笔记十五

虚函数和多态性
               
      使用基类指针,示例代码如下(从Box派生两个类) 
      class Carton:public Box{
           
      };
      class ToughPack:public Box{
           
      };


       Carton aCarton(10.0,10.0,5.0);
       Box * pBox=& aCarton;
 
       ToughPack hardcase(12.0,8.0,4.0);
       pBox=&hardcase;
  
        有如下语句:pBox()->volume; 此时如pBox包含的是Carton的对象地址,那


么它指向的就是Carton对象的函数,同理hardcase也一样
      


       调用继承的函数 


        头文件Box.h
        #ifndef BOX_H
        #define BOX_H
      ================ 基类=========================================
        class Box{
            //构造器
            public:
              Box(double lengthValue=1.0,double widthValue=1.0,double 


heightValue=1.0);
            
            //成员函数
            void showVolume() const;
            double volume() const;


   //成员变量
            protected:
                double length; 
                double width;
                double height;
        };
        #endif
      ==================================================================
       实现文件Box.cpp
        #include "Box.h"
        #include <iostream>
        using std::cout; 
        using std::endl;
          
        //构造函数
        Box::Box(double lvalue,double wvalue,double hvalue):length


(lvalue),width(wvalue),height(hvalue){}
      
        void Box::showVolume() const{
            cout<<"Box usable volume is "<<volume()<<endl;
        }
 
        double Box::volume() const{
            return length*width*height;
        }
      =================派生类============================================
        头文件ToughPack.h
        #ifndef TOUGHPACK_H
        #define TOUGHPACK_H
        
        #include "Box.h"
        
        class ToughPack:public Box{
           public:
              ToughPack(double lengthValue,double widthValue,double 


heightValue);
              double volume() const;
        }  
      ===================================================================
        实现文件ToughPack.cpp  
         #include "ToughPack.h"
         
         ToughPack::ToughPack(double lval,double wval,double hval):Box


(lval,wval,hval){}
         double ToughPack::volume() const{
             return 0.85*length*width*height;
         }   
      ====================================================================
      使用继承的函数   
      #include <iostream>
      #include "Box.h"
      #include "ToughPack.h"
      using std::cout;
      using std::endl;
  
      int main(){
          Box myBox(20.0,30.0,40.0);
          ToughPack hardcase(20.0,30.0,40.0);
          
          cout<<endl;
          myBox.showVolume();//调用基类函数
          hardcase.showVolume();//调用派生类函数
       
          return 0;
      }
      如果想直接调用ToughPack中的valume()方法,示例代码如下:
      cout<<"hardcase volume is"<<hardcase.volume()<<endl;
      Box *pBox =&hardcase;
      cout<<"hardcase volume through pBox is"<<pBox->volume()<<endl;      
 
      虚函数
      一个基类中如果定义了虚函数,那么在派生于这个类的任何类,该函数都是动态


绑定的.(virtual)  使用对象的引用或指针都可以调用虚函数
      注: 每个派生类都可以执行虚函数的自有版本
       示例代码
       class Box {
          //构造器
          public:
             Box(double lenthValue=1.0,double widthValue=1.0,double 


heightValue=1.0);
         
          void showVolume() const;

          //虚函数
          virtual double volume() const;
 
          //成员变量
       protected:
             double length;
             double width; 
             double lenght;
       }
       =================================================================
       Carton.h头文件
       #ifndef CARTON_H
       #define CARTON_H
       #include <string>
       #include "Box.h"
       using std::string;
 
       class Carton:public Box{
           //构造函数
           pulbic:
              Carton(double lv,double wv,double hv,string 


material="Cardboard");
           //副本构造成器
           Carton(const Carton & aCarton);
   
           //析构函数 
           double volume() const; 
          
           //成员变量
           private:
               string * pMaterial;
      };
      #endif
      ==========================================================
      实现文件Carton.cpp
      #include "Carton.h"
      Carton::Carton(double lv,double wv,double hv,string material):Box


(lv,wv,hv){
                pMaterial=new string(material);       
       }
      Carton::Carton(const Carton & aCarton){
         length=aCarton.width;
         width=aCarton.height;
         height=aCarton.width;
         pMaterial=new string (* aCarton,pMaterial);
      }
      
      Carton::~Carton(){
          delete pMaterial;
      }
  
      double Carton::volume() const{
           double vol-(length-0.5)*(width-0.5)*(height-0.5);
           return vol>0.0?vol:0.0;
      }


     =============================================================
       调用访函数的示例代码如下:
       #include <iostream>
       #include "Box.h"
       #include "ToughPack.h"
       #include "Carton.h"
       using std::cout;
       using std::endl; 
      
       int main(){
          Box myBox(20.0,30.0,40.0);
          ToughPack hardcase(20.0,30.0,40.0); 
          Carton aCarton(20.0,30.0,40.0);
      
          //显示三个对象的体积
          cout<<endl;
          myBox.showVolume();
          hardcase.showVolume();
          aCarton.showVolume();
          cout<<endl;
      
          pBox=& hardcase; 
          cout<<"hardcase volume through pBox is"<<pBox->volume()<<endl;
          pBox->showVolume();
          cout<<endl;
         
          pBox=& aCarton;
          cout<<"aCarton volume through pBox is"<<pBox->volume()<<endl;
          pBox->showVolume();


          return 0;
       }
   
       虚函数中的默认参数值
         如果在基类的虚函数中使用默认参数,在通过基类指针调用该函数时,只会


使用基类中的默认参数 


       头文件Box.h
      #ifndef BOX_H
      #define BOX_H
      
      class Box {
          //构造器
          public:
             Box(double lenthValue=1.0,double widthValue=1.0,double 


heightValue=1.0);
         
          void showVolume() const;

          //虚函数
          virtual double volume(const int i=5) const;
 
          //成员变量
       protected:
             double length;
             double width; 
             double lenght;
       };
       #endif


      ====================================================================
          实现文件Box.cpp
        #include "Box.h"
        #include <iostream>
        using std::cout; 
        using std::endl;
          
        //构造函数
        Box::Box(double lvalue,double wvalue,double hvalue):length


(lvalue),width(wvalue),height(hvalue){}
      
        void Box::showVolume() const{
            cout<<"Box usable volume is "<<volume()<<endl;
        }
 
        //使用默认参数
        double Box::volume(const int i) const{
   cout<<"Parameter"<<i<<endl;
            return length*width*height;
        }
       ====================================================================
         派生类 头文件ToughPack.h
         #ifndef TOUGHPACK_H
         #define TOUGHPACK_H
         
         #include "Box.h"
 
         class ToughPack:public Box{
              //构造成器
              public:
                 ToughPack(double lengthValue,double widthValue,double 


heightValue);
              //虚函数
              virtual double volume(const int i=500) const;
         };
         #endif
       ===================================================================
 
        实现文件ToughPack.cpp
        #include "ToughPack.h"
        #include <iostream>
        using std::cout;
        using std::endl;
           ToughPack::ToughPack(double lVal,double wVal,double hVal):Box


(lVal,wVal,hVal){}
           double ToughPack::volume() const{ 
              cout<<"Parameter"<<i<<endl;
              return 0.85*length*width*height;
           }
      =====================================================================
      调用时
       #include <iostream>
       #include "Box.h"
       #include "ToughPack.h"
       #include "Carton.h"
       using std::cout;
       using std::endl;      
 
       int main(){ 
           Box myBox(20.0,30.0,40.0);
          ToughPack hardcase(20.0,30.0,40.0); 
          Carton aCarton(20.0,30.0,40.0);
 
          cout<<endl;
          myBox.showVolume();     
          hardcase.showVolume();
          aCarton.showVolume();
          cout<<endl;
   
          cout<<"hardcase volume is"<<hardcase.volume()<<endl;


          Box pBox=& myBox; 
          cout<<"myBox volume through pBox is"<<pBox->volume()<<endl;
          pBox->showVolume();
          cout<<endl;


  pBox=& hardcase; 
          cout<<"hardcase volume through pBox is"<<pBox->volume()<<endl;
          pBox->showVolume();
          cout<<endl;
         
          pBox=& aCarton;
          cout<<"aCarton volume through pBox is"<<pBox->volume()<<endl;
          pBox->showVolume();
          
          return 0;
      
      }




       通过引用来来调用虚函数
        对虚函数的引用
        #include <iostream>
        #include "Box.h"
        #include "ToughPack.h"
        #include "Carton.h"
        using std::cout;
        using std::endl; 
        
        void showVolume(const Box & rBox);
       
        int main(){ 
          Box myBox(20.0,30.0,40.0);
          ToughPack hardcase(20.0,30.0,40.0); 
          Carton aCarton(20.0,30.0,40.0);
 
          cout<<endl;
          showVolume(myBox);
          showVolume(hardcase);
 showVolume(aCarton);
 
           return 0;
        }
         
         void showVolume(const Box & rBox){
             rBox.showVolume();
         }


        调用虚函数的基类版本 示例代码如下:
         通过派生类对像的指针或引用虚函数的派生类版本
         Carton aCarton(40.0,30.0,20.0)
         Box* pBox=&aCarton;
         计算Carton对像的总体积损失:
         double difference=pBox->Box::volume()->pBox->volume();


        pBox->Box::volume() 
 
    在指针和类对像之间的转换
     如果程序包含派生类的指针,就可以把指针隐式转换为基类指针,(可以是直接基


类指针,也可以是间接基类指针)
    例如:
     Carton * pCarton=new Carton(30,40,10);
     可以把这个隐式指针转换为Carton的直接基类指针,
       Box * pBox=pCarton;
     还可以把派生类的隐式指针转换为间接基类的指针,示例化码如下:
      CerealPace继承Carton,carton继承Box
      Box* pBox=pCerealPack;//把pCerealPack中的地址从“指向CerealPack”的指


针类型转换为"指向Box"的指针类型
      如果要指定显示转换,可以使用static_case<>()运算符
      Box* pBox=static_case<Box*>(pCerealPack);






     动态强制转换 (只能应用于多态类类型的指针和引用,即至少包含一个虚函数的


类类型)
     在使用期间,要指定动态强制转换,应使用dynamic_case<>()运算符
     动态转换指针 
     动态制转换有两种类型:
        一种是沿着类层次结构向下进行强制转换(从直接或间接基类的指针转换为派


生类型的指针,称为downcast)
         示例代码如下:
                                        目标类型 要强制转换为新类型的表达式
          Carton * pCarton=dynamic_cast<Carton*> (pBox);
         注:Carton和Box必须包含虚函数
        另一种是跨类层次的强制转换,称为crosscast
          Contents* pContents=dynamic_cast<Contents*>(pBox);
          注: Contents和Box类都必须是多态性的
 
       假定一个Box对象指向某个对象,如果想调用Carton类的一个非虚函数
         基类指针只允许调用派生类的虚函数,而dynamic_cast<>()运算符可以调用


非虚函数
        示例代码:如果想调用Carton类的一个非虚函数在员surface()方法
         dynamic_cast<Carton*>(pBox)->surface();
         注:这样作的前提是确保pBox指向Carton对象或指向Carton作为基类的对象
         正确写法:
         if(Carton* pCarton=dynamic_cast<Carton*>(pBox)){
                pCarton->surface();
          }
          
          注:如果要强制转换的指针类型是const,则目标类型也必须是const,
              如果把const指针转换为非const类型指针,就必须使用const_cast<>()


        转换引用(函数的引用参数)
        示例人代码如下:
         double doThat(Box & rBox){
             Carton& rCarton=dynamic_cast<Carton&>(rBox);
         }


    多态性的成本   ( 虚函数的调用需要额外和开销)
      简单的说包含相同数据成员,含有虚函数的类要比没有的类占用的内存要多
      内存使用多的原因:在创建多态类的对象,要在对象中创建一个特殊指针(用


于调用对象中的虚函数)      
    纯虚函数(类似于接口-所有的成员都有是抽象成员)
      示例代码如下:
      class Shape{
         public:
             virtual void draw() const=0;
             virtual void move(const Point& newPosition)=0;
     
         protected:
              Point position;
              Shape(const Point& shapePosition):position(shapePosition){} 
      };


      抽象类(抽象类的指针或引用可以用作参数或返回类型)
      
         抽象类的构造函数可以在派生类的构造函数的初始化列表中调用(一般为


protected类型)
        示例代码:声明一个新类,它把shape类作为基类
          class Circle:public Shape{
               public :
                   Circle(Point center,double circleRadius):Shape(),radius


(circleRadius){}
               virrual void draw() const{
                   cout<<"Circle center"<<position<<"radius"<<radius<<endl;
                }
        virrual void move(const Point& newCenter){
                   position=newCenter;  
                }
               private:
                 double radius;
          }
          注: Circle类定义了draw()和move()函数, 如果没有定义这两个方法中的


任何一个,Circle就是一个构造类
           如果类中有一个纯虚函数,该类就是抽象类,派生类必须定义基类中的每


个纯虚函数,否则派生类也是一个抽象类,当然抽象类还可以包含非纯虚函数


          示例代码:
          class Box{
              public: 
                 Box(double lengthValue=1.0,double widthValue=1.0,double 


heightValue=1.0);
              protected:
                double length;
                double width;
                double height;
          }; 
          
           #include<iostream>
           #include "Box.h"
           #include "ToughPack.h"
           #include "Carton.h"
           using std::count;
           using std::endl;
  
           int main(){
             cout<<endl;
     
             ToughPack hardcase(20.0,30.0,40.0);
             Box* pBox=&hardcase;
             cout<<"Volume of hardcase is"<<pBox->volume()<<endl;


             Carton aCarton(20.0,30.0,40.0);
             pBox=&aCarton;
             cout<<"volume of aCarton is"<<pBox->volume()<<endl;
           
             return 0;
           }
        
       用接口的抽象类 (只有包含一个纯虚接口的抽象类可以用于定义标准类接口)
     
       间接的抽象类
            多级继承  示例代码
            vessel为Box的基类
           头文件如下
            #ifndef VESSEL_H
            #define VESSEL_H
            
             class Vessel{
               public:
                   virrual double volume() const=0;// 虚函数
            };
            #endif
          
           Box类的头文件为:
            #ifndef BOX_H
            #define BOX_H
            #include "Vessel.h"
            class Box:public Vessel{
           public:
                    Box(double lengthValue=1.0,double widthValue=1.0,double 


heightValue=1.0);
                  virtual double volume() const;//不是纯虚状态
                  protected:
                     double length;
                     double width;
                     double height;
            };
            #endif
         
            实现文件Box.cpp
             double Box::volume() const{
                 return length * width* height;
             }
          
           另一个vessel中另一个派生类can,头文件can.h
           #ifndef CAN_H
           #define CAN_H
           
           #inclued "Vessel.h"
           class Can:pulbic Vessel{
              public :
                  Can(double canDiameter,double canHeight);
                  virtual double volume() const;//
              protected:
                  double diameter;
                  double height;
                  static const double pi;//虚函数              
            };
            #endif
            实现文件can.cpp
            #include "Can.h"
            Can::Can(double canDiameter,double canHeight):diameter


(canDiameter),height(canHaight){}
          
            double Can:volume() const{
               return pi* diameter*diameter*height/4;
            }
            const double Can::pi=3.1415926;
            


            
           测试主函数
          #include <iostream>
          #include "Box.h"
          #include "ToughPack.h"
          #include "Carton.h"
          #include "Can.h"
          
          using std::cout;
          using std::endl;


          int main(){
             //初始化容器
             Box aBox(40,30,20);
             Can aCan(10,3);
             Carton aCarton(40,30,20);
             ToughPack hardcase(40,30,20);


             Vessel* pVessels[]={&aBox,&aCan,&aCarton,&hardcase};
 
             cout<<endl;
             for(int i=0;i<sizeof pVessels/sizeof(pVessels[0]);i++){
                 cout<<"Volume is"<<pVessels[i]->value<<endl; 
             }
              return 0;
          }
      
     通过指针释放对象 
        示例代码如下:
        在vesel类的头文件中添
        class Vassel{
            public:
               virtual double volume() const=0;// 虚函数
               ~Vessel();//析构函数
        }
        实现文件中添加如下代码
        #include <iostream>
        #include "Vessel.h"
        
        Vessel::~Vessel(){
           sed::cout<<"Vessel destructor"<<std::endl;       
       }
       在派生类加添加相同的输出一句
  
       测试主函数如下:
         #include <iostream>
          #include "Box.h"
          #include "ToughPack.h"
          #include "Carton.h"
          #include "Can.h"
          
          using std::cout;
          using std::endl;


          int main(){
             //初始化容器
             Box aBox(40,30,20);
             Can aCan(10,3);
             Carton aCarton(40,30,20);
             ToughPack hardcase(40,30,20);


             Vessel* pVessels[]={&aBox,&aCan,&aCarton,&hardcase};
 
             cout<<endl;
             for(int i=0;i<sizeof pVessels/sizeof(pVessels[0]);i++){
                 cout<<"Volume is"<<pVessels[i]->value<<endl; 
             }
             //释放资源
             for(int i=0;i<sizeof pVessels/sizeof(pVessels[0]);i++){
                  delete pVessels[i];
             }
              return 0;
          }


          结果是几个类在释放资源时都调用基类Vessel destructor的析构函数


          虚析构函数
             在析构函数声明中添加关键字virtual
             调用虚拟析构函数,示例代码如下:
             class Vessel{
                 public :
                    virtual double volume() const=0;//虚函数
                    virtual ~vessel();//虚析构函数
             };
          


           在运行期间标识类型
             检查指针指向类型 (typeid()运算符,需在头文件中包含<typeinfo>



             if(typeid(* pVessel)==typeid(Carton)){
                  cout<"Pointer is type Carton"<<endl;
             }else{
                  cout<"Pointer is not type Carton"<<endl;
             }


       


       类成员的指针
         数据成员指针 它包含类成员的地址,仅在与类对象组合使用时,才指向内


存的某个位置 
         示例代码如下:
           class Box{
              public :
                 Box( Box(double lenthValue=1.0,double 


widthValue=1.0,double heightValue=1.0);
                 void showVolume() const;
              public :             //原始状态为protected
                 double length;
                 double width;
                 double height;
           }
 
            //定义一个指针
            double Box::* pData;
          //注创建同意词的语名
            typedef double Box:: * pBoxMember;//pBoxMember替代double Box::*
          //下面的语句把类成员width的地址赋于这个指针
           pData=&Box::width;
 
          "成员指针"选择运算符
          成员指针总是要和对象、对象的引用或对象的指针一起使用
            示例代码如下:
             Box myBox(20.0,30.0,40.0);
          调用myBox的width成员
            myBox.*pData




           应用Box指针
           Box* pBox=&myBox;
           通过指针访问myBox 中的数据成员
             pBox->*pData//此处用到间接成员指针->*
           
           使用成员指针,示例代码
          #include <iostream>
          #include "Box.h"
          #include "ToughPack.h"
          #include "Carton.h"
          
          using std::cout;
          using std::endl;
         
          typedef double Box::* pBoxMember;  
          int main(){
              //初始化三个容器
              Box myBox(20.0,30.0,40.0);
              ToughPack hardcase(35.0,45.0,55.0);
              Carton aCarton(48.0,58.0,68.0);
              //使用成员指针,指向成员长度
              pBoxMember pData=&Box::length;
                 
              cout<<endl;
 
              cout<<"Length member of myBox is"<<myBox.*pData<<endl;
              pData=&Box::width;//指向成员宽度


              cout<<"width member of myBox is"<<myBox.*pData<<endl;
              pData=&Box::height;//指向成员高度


              cout<<"height member of myBox is"<<myBox.*pData<<endl;
              cout<<"height member of hardcase is"<<hardcase.*pData<<endl;
              cout<<"height member of aCarton is"<<aCarton.*pData<<endl;
              
              //利指针访问成员指针中的成员
               Box* pBox=&myBox;
                
              cout<<"height memeber myBox is"<<pBox->*pData<<endl;
               pBox=&hardcase;
        
               cout<<"height memeber hardcase is"<<pBox->*pData<<endl;
               cout<<endl;
               return 0;              
          }
posted @ 2012-09-20 23:36  retacn_yue  阅读(175)  评论(0编辑  收藏  举报