1. 程式人生 > >繼承多型與虛擬函式及對類的理解

繼承多型與虛擬函式及對類的理解

    B是A的子類,子類會繼承父類的public方法,子類物件可以呼叫父類的public介面,但是子類和父類函式重名時,父類的方法會被子類覆蓋(隱藏),子類呼叫和父類同名同參函式或者過載父類的函式後不可以直接呼叫父類函式,需要加A::fun()呼叫,父類的protect方法只在繼承中有效,子類可以呼叫父類的protect方法,但是外部無法訪問,所以在非繼承關係中protect與private等同,private方法只能由類內部的方法呼叫,也可以由友元函式和類呼叫,其他物件都不可以訪問類的private資料。

     父類物件指向子類時只能呼叫子類從父類繼承到的一部分函式,不可以呼叫子類新增的函式,所以指標向上轉化是安全的,向下轉化有問題,dynamic_cast會返回一個空指標。多型是指父類物件可以指向並呼叫子類中和父類同名同參函式,通過虛擬函式來實現,父類中定義的虛擬函式在子類不定義也是虛擬函式。虛擬函式通過虛擬函式表實現,32位機器的編譯器有虛擬函式的類會多出4個位元組的虛擬函式指標,指向虛擬函式表中的第一個虛擬函式,當父類物件指向子類並呼叫虛擬函式的時候,便從子類的虛擬函式表中找出對應的同名同參函式。純虛擬函式是如同virtual fun(){}=0的函式,存在純虛擬函式的類稱為抽象類(純虛類),抽象類不可以建立例項物件,只能由子類重寫其純虛擬函式。舉個例子就如動物類virtual eat(){}=0而狗類virtual eat(){cout<<"bone"<<endl;}一個抽象類可以定義多個虛擬函式,均通過指向不同的子類物件由子類物件例項化,若子類未例項化純虛擬函式,則子類也為抽象類,等待孫子類來例項化純虛擬函式,才可以建立物件。純虛類和虛基類不同,虛基類僅僅出現在多重繼承關係中,虛繼承使多個派生類共用一份基類的成員(基類必須使用預設建構函式才可以虛繼承),並消除菱形繼承中的孫子類歧義,應儘量避免多重繼承的使用。

    類是物件的抽象,物件是類的例項。一個空類中存在預設建構函式,預設解構函式,預設拷貝建構函式(淺拷貝),預設運算子過載“=”,預設取地址符&和const取地址符&,當使用const取址的時候,需要注意const在*之後是說指標不允許指向其他的物件,而const在*之前才是說不允許使用指向該類的指標改變該類的任何成員,而且只能呼叫類的const方法。還有一個需要注意的是new和malloc可以在堆中建立物件,但malloc只是庫函式,而new是運算子,只有new可以建立類物件,因為new可以自動呼叫類的預設建構函式並建立類的例項而malloc不可以。在類的內部一旦發生在堆上使用malloc或者new申請空間的事件的時候,需要注意預設拷貝建構函式和預設過載運算子“=”可能導致指標懸空問題,可能導致兩個物件同時指向堆中的一塊空間,在析構的時候會導致重複析構。如果需要用,需要重寫預設拷貝建構函式和“=”過載,為新物件在堆中申請相應的空間。深拷貝:

  1. Person(const Person &p)  
  2. {  
  3.     m_name = newchar[strlen(p.m_name)+1];  
  4.     if (m_name != 0)  
  5.     {  
  6.         strcpy(m_name,p.m_name);  
  7.         m_age = p.m_age;  
  8.     }  
  9. }  
在傳引用引數前加const主要是防止不小心修改原有資料,儘量在不會更改原有資料的所有情況下加const限定防止出錯。     對類的構造可以使用成員初值列
  1. class STU  
  2. {  
  3. public:  
  4. STU(string _name,string _sex,
    int _age):name(_name)  
  5.     {  
  6.         sex=_sex;  
  7.         age=_age;  
  8.     }  
  9.     void printStu()  
  10.     {  
  11.         cout<<"姓名:"<<name<<endl<<"性別:"<<sex<<endl<<"年齡:"<<age<<endl;  
  12.     }  
  13. private:  
  14.     string name;  
  15.     string sex;  
  16.     int age;  
  17. };  
當構造子類的時候,構造順序應該是先父類,然後構造子類裡的物件,然後構造子類自身。若父類或子類中的物件存在自定義的含參建構函式,必須先構造他們才能構造子類。         在繼承關係中,要將父類的解構函式宣告為虛擬函式,防止父類指標指向子類的時候,無法析構子類而只析構父類。
#include <iostream> using namespace std; class Person{ public: ~Person(){  //declare destructor as a virtual function cout << "Person::~Person()" << endl; } }; class Student : public Person{ public: ~Student(){     // virtual or not is OK cout << "Student::~Student()" << endl; } }; int main(){ Person *pt1 = new Person; Person *pt2 = new Student;        // base class pointer point to derived class // Student *pt3 = new Person;     // derived class pointer can not point to base class Student *pt4 = new Student; delete pt1; cout << "*********" << endl; delete pt2; cout << "*********" << endl; //delete pt3; //cout << "*********" << endl; delete pt4; cout << "*********" << endl; return 0; }

執行結果:

設計一個不能繼承的類:
  1. #include<iostream>
  2.   using namespace std;
  3.   template <typename T> 
  4.   class Base
  5.   {
  6.   friend T;
  7.   private:
  8.   Base() {}
  9.   ~Base() {}
  10.  };
  11.  class Finalclass : virtual public Base<Finalclass>
  12.  { 
  13.  public:
  14.  Finalclass() {}
  15.  ~Finalclass() {}
  16.  };
  17.  void main()
  18.  {
  19.  Finalclass *= new Finalclass; //堆上物件
  20.  Finalclass fs; //棧上物件
  21.  }