一、类的继承
          派生类不继承的基类成员仅有析构函数、构造函数以及任何重载赋值运算符的成员函数。
          所有其他函数成员,连同基类的所有数据成员,都将被派生类继承。
          特别注意:析构函数、构造函数、重载赋值运算符是不能被派生类继承的。
          1、派生类声明
              class CBox
              {
                 public:
                     double m_Length;
                     double m_Width;
                     double m_Height;
                    
                     CBox(double lv=1.0,double wv=1.0,double hv=1.0):
                                m_Length(lv),m_Width(wv),m_Height(hv){};                                              
              };
             
              class CCandyBox:CBox   默认是私有继承。等同:class CCandyBox:private CBox;
              {                      如果省略基类的访问说明符,则编译器将默认该说明符
                 pulbic:             是private.
                     char* m_Contents;
                     CCandyBox(char* str="Candy")
                     {
                        m_Contents= new char[strlen(str)+1];
                        strcpy_s(m_Contents,strlen(str)+1,str);
                     }
                     ~CCandyBox()
                     {delete[] m_Contents;};
              };
          2、派生类的使用
              CCandyBox myCandyBox;   CCandyBox共占有32个字节,其中24个字节来此基类CBox,
                                      4个字节来此本类的char*指针,另外4个字节
                                      是编译器要在8个字节的倍数地址上对齐成员,自动补了4个字节。
          3、继承机制下的访问控制
             派生类继承下了基类的所有数据,其实派生类就是父类和派生类新方法的叠加。
             只是派生类不能访问父类的私有成员。
          4、派生类的构造函数
              虽然说派生类不会继承基类的构造函数,但它们仍然存在于基类中,并且要用于创建派
              生类对象的基类部分。因为创建派生类对象的基类部分实际上属于基类构造函数而非派
              生类构造函数的任务。基类的私有成员在派生类中虽然被继承下来,但是不可访问。
             
              如果基类被声明为private,其成员在派生类中永远都不可访问。
              如果基类被声明为public, 其成员在派生类中的访问级别保持不变。
              如果基类被声明为protected,其成员public成员在派生类中将成为protected。
             
              在为派生类编写构造函数时,需要初始化包括继承成员在内的派生类对象的所有成员。
          5、派生类中的复制构造函数
              如果给派生类定义复制构造函数,那么请在派生类复制构造函数中合理的初始化基类。
              特别注意:基类中的成员变量 有动态分配的内存,那么派生类复制构造函数中一定得
              调用基类复制构造函数。如果基类没有复制构造函数,那么就人工给基类添加复制构造函数。
二、友元类成员
         class CBottle
         {
           public:
               CBottle(...)
               {
                   ...
               }
           private:
               friend CCArton;       CBottle类中有了这条声明语句之后,CCarton类的
         }                           所有函数成员就都能自由访问CBottle类的所有数据成员。
         使CCarton类成为CBottle类的友元,并不意味着CBottle类也是CCarton类的友元,人工希望如此,
         则必须在CCarton类中将CBottle类声明为友元。
         类友元关系还是不可继承的,人工我们以CBottle为基类定义了另一个类,则CCarton类的成员将
         无权访问该派生类的数据成员,即使这些成员是从CBottle类继承的也不行。
三、虚函数
       虚函数是以virtual关键字声明的基类函数。如果在基类中将某个函数指定为virtual,并且派生类
       中有另外一个该函数的定义,则编译器将知道我们不想静态链接该函数,我们真正需要的是基于调
       用该函数的对象种类,在程序的特定位置选择调用那个函数。
       1、虚函数定义
         class CBox                             基类
         {
             public:
                  void ShowVolume() const
                  {
                      cout<                   }
                  virtual double Volume() const  虚函数定义:只要在普通函数前面加上virtual关键字即可。
                  {
                      ...
                  }
         };
         class CGlassBox:public CBox             派生类
         {
            public:
               virtual double Volume() const    虽然我们在派生类Volume()函数定义中使用了virtual关键字,
               {                                但这样做不是必需的,在基类中将该函数定义为virtual已经
                  ...                           足够了。不过建议在派生类中为虚函数指定virtual关键字,
               }                                因为这样可以使阅读派生类定义的任何人都清楚地知道这些
         };                                     函数是动态选择的虚函数。
         要使某个函数表现出虚函数的行为,该函数在任何派生类中都必须有与基类函数相同的名称,形参列表
         和返回类型。如果基类函数是const,那么派生类中的函数也必须是const。如果使用不同的形参和返回
         类型,或者将一个声明为const,而另外一个不然,则虚函数机制将不能工作。
        
         从派生类函数的观点来看,CGlassBox派生类中的Volume()函数实际上隐藏了该函数的基类版本。
         如果我们希望从某个派生类函数中调用基类的Volume()版本,则需要以CBox::Volume()这样的形式使用
         作用域解析运算符来引用基类函数。
四、使用指向类对象的指针
         CBox myBox(2.0,3.0,4.0);
         CGlassBox myGlassBox(2.0,3.0,4.0);
         CBox* pBox=0;
        
         pBox=&myBox;
         pBox->ShowVolume();       调用的是myBox的ShowVolume函数。
         pBox=&myGlassBox;
         pBox->ShowVolume();       调用的是myGlassBox的ShowVolume函数。
        
         虚函数机制借助于指向基类的指针同样能够正常工作,实际调用的函数是基于被指向
         的对象类型而选择的。
                      
五、使用引用处理虚函数
                       
        void Output(const CBox& aBox)
        {
            aBox.ShowVolume();
        }
       
        CBox myBox(2.0,3.0,4.0);
        CGlassBox myGlassBox(2.0,3.0,4.0);
       
        Output(myBox);                            调用的是myBox的ShowVolume函数。
        Output(myGlassBox);                       调用的是myGlassBox的ShowVolume函数。
       
       
        class CBox;                CBox类的不完整定义,好像delphi中的forword声明。
六、抽象类
      1、抽象类声明
     
            class CContainer                           抽象类:包含纯虚函数的类被成为抽象类,因为
            {                                          我们不能定义包含纯虚函数的类的对象,抽象类存
               public:                                 在的唯一用途,就是定义派生类。  
                                                       如果抽象类的派生类将基类的纯虚函数仍然定义为纯虚函数,
                                                       在该派生类也是抽象类。
                   virtual double Volume() const=0;    纯虚函数。
                  
                   virtual void ShowVolume() const
                   {
                       Volume();
                   }
            };
           我们已经将Volume()声明为const,所以在任何派生类中该函数的实现也都必须是const.记住,
           即使名称和形参列表相同,但函数的const和非congst变体也是不同的函数,换句话说,我们
           可以使用congst来重载函数。
           如果我们忘记将派生类的Volume()函数指定为const,则派生类同样将仍然是抽象类,因为它
           不仅包含我们定义的非const函数Volume(),还包含const纯虚函数成员Volume();

七、类类型之间的强制转换
          CContainer* pContainer=new CGlassBox(2.0,3.0,4.0);
          CBox* pBox=dynamic_case(pContainer);                将pContainer强制转换为CBox*;
          CGlassBox* pGlassBox=dynamic_case(pContainer); 将pContainer强制转换为CGlassBox*; 
                 
八、嵌套类