程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++之父力作學習筆記6——派生類

C++之父力作學習筆記6——派生類

編輯:C++入門知識

現在來考慮做一個程序,處理某公司所雇傭人員的問題。這個程序可能包含如下一種數據結構: struct Employee
{
    string first_name,family_name;
    char middle_initial;
    Date hiring_date;
    short department;
    //
};下一步我們可能需要去定義經理: struct Manager
{
    Employee emp;
    list<Employee*> group; //所管理的人員
    short level;
    //
};一個經理同時也是一個雇員,所以在Manager對象的emp成員存儲著Employee數據。很明顯這樣的設計是糟糕的,大家都會想到派生:
struct Manager:public Employee
{
    list<Employee*> group;
    short level;
};這個Manager是由Employee派生的,反過來就是說,Employee是Manager的一個基類。類Manager包含類Employee得所有成員,再加上它自己的一些成員。
      按照這種方式從Employee派生出Manager,就使Manager成為Employee的一個子類型,使Manager可以用在能夠接受Employee的任何地方。因為Manager是Employee,所以Manager*就可以當做Employee*使用。然而,因為Employee不一定是Manager,所以Employee*就不能當做Manager*用。總而言之類Derived有一個公用基類Base,那麼就可以用Derived*給Base*類型的變量賦值,不需要顯示的類型轉換。而相反的方向,從Base*到Derived*則必須顯示轉換。例如: void g(Manager mm,Employee ee)
{
    Employee* pe = &mm;  //可以:Manager都是Employee
    Manager* pm = &ee;   //錯誤:Employee不一定是Manager
    pm->level = 2;       //災難:ee沒有level
    pm = static_cast<Manager*>(pe);//蠻力:這個可以,因為pe指向的是Manager mm
    pm->level = 2;       //沒問題
}
      派生類的成員可以使用其基類的公用的和保護的成員,但是,派生類不能使用基類的私有成員。對於派生類的成年公園而言,保護成員就像是公用成員;但對於其他函數它們則像是私用成員。
      下面說說派生類的構造函數和析構函數
      有些派生類需要構造函數。如果某個基類中有構造函數,那麼就必須調用這些構造函數中的某一個。默認構造函數可以被隱含的調用,但是,如果一個基類的所有構造函數都有參數,那麼就必須顯示的調用其中的某一個。基類構造函數的參數應在派生類構造函數的定義中有明確描述。在這方面,基類的行為恰恰就像是派生類的一個成員。例如: Employee::Employee(const string& n,int d):family(n),department(d)
{
    //
}

Manager::Manager(const string& n,int d,int lvl):Employee(n,d),/**//*初始化基類*/level(lvl)/**//*初始化成員*/
{
    //
}派生類的構造函數只能描述它自己的成員和自己的直接基類的初始式,它不能直接去初始化基類的成員,例如:
Manager::Manager(const string& n,int d,int lvl):family_name(n).department(d),level(lvl)//錯誤:在Manager裡沒有family_name和department的聲明
{
//
} 類對象的構造是自下而上進行的:首先是基類,而後是成員,再後才是派生類本身。類對象的銷毀則正好以相反的順序進行:首先是派生類本身,而後是成員,再後才是基類。
      對於給定的一個類型為Base*的指針,被指的對象到底屬於哪個派生類型呢?這個問題有四種基本的解決方案:
 保證被指的只能是唯一類型的對象

在基類裡安排一個類型域,供函數檢查

 使用dynamic_cast

 使用虛函數 
       從Employee的函數中取得“正確的”行為i,而又不依賴於實際使用的到底是哪一種Employee,這就是所謂的多態性。一個帶有虛函數的類型被稱為是一個多態類型。要在C++裡取得多態行為,被調用的函數就必須是虛函數,而對象則必須是通過指針或者引用去操作的。如果直接操作一個對象(而不是通過指針或引用),它的確切類型就已經為編譯器所知,因此也就不需要運行時的多態性了。
      那麼一個虛函數聲明為純虛函數,則這個虛函數所在的類為抽象類。用=0作為初始式就使虛函數成為“純虛的”。注意:不能創建抽象類的對象。抽象類只能做界面,作為其他類的基類。還有一點也要指的注意,一個未在派生類裡定義的純虛函數仍舊還是一個純虛函數,這種情況也將使該派生類仍為一個抽象類。例如:

class Shape
{
     public:
        virtual void draw()=0;
        virtual bool isClose()=0;
     //
};

class Circel:public Shape
{
    public:
       bool isClose(){return true;}//覆蓋Shap::isClose
       //draw尚未覆蓋
};

Circel a;//錯誤:聲明的是抽象類Circel對象
抽象類的最重要用途就使提供一個界面,而又不是暴露任何實現的細節。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved