小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

C++ 面向?qū)ο缶幊?/span>

 thchen0103 2017-02-02
C++ 面向?qū)ο缶幊?/strong>
     面向?qū)ο缶幊袒谌齻€(gè)基本概念:數(shù)據(jù)抽象、繼承動(dòng)態(tài)綁定
1 基類(lèi)和派生類(lèi) 
1.1 定義基類(lèi) 
    在基類(lèi)中,除了構(gòu)造函數(shù)之外,任意非 static 成員函數(shù)都可以是虛函數(shù)。
     基類(lèi)通常應(yīng)將派生類(lèi)需要重定義的任意函數(shù)定義為虛函數(shù)。 
 
1.2 訪問(wèn)控制 
(1)private  成員
·  通過(guò)類(lèi)對(duì)象無(wú)法訪問(wèn)類(lèi)的private成員。
·  在派生類(lèi)中不能訪問(wèn)基類(lèi)的private成員。 
·  private 成員只能在當(dāng)前類(lèi)的作用域內(nèi)訪問(wèn),類(lèi)的友元也可以訪問(wèn)類(lèi)的private 成員。例如,在成員函數(shù)中可以訪問(wèn)private 成員,在成員函數(shù)中還可以通過(guò)自己類(lèi)的對(duì)象來(lái)訪問(wèn)類(lèi)的private 成員。類(lèi)的作用域包括:類(lèi)定義的{}之內(nèi),類(lèi)定義之外的成員函數(shù)的函數(shù)體,形參列表等。
class Base
{
public:
     void Test1(Base& b)
     {
          b.iBase = 0;//有沒(méi)有問(wèn)題?
     }
private:
     int iBase;
};
 
class Derived : public Base
{
public:
     void Test2(Base& b)
     {
          b.iBase = 0;//有沒(méi)有問(wèn)題?
     }
     void Test3(Derived& d)
     {
          d.iDerived = 0;//有沒(méi)有問(wèn)題?
     }
private:
     int iDerived;
};
 
 
(2)protected  成員
·  通過(guò)類(lèi)對(duì)象無(wú)法訪問(wèn)protected 成員。 
·  protected 成員可被public派生類(lèi)(包括派生類(lèi)的派生類(lèi),向下傳遞)訪問(wèn),也就是說(shuō)在派生類(lèi)中可以使用基類(lèi)的protected 成員。 
·  派生類(lèi)只能通過(guò)派生類(lèi)對(duì)象訪問(wèn)其基類(lèi)的 protected 成員,派生類(lèi)無(wú)法訪問(wèn)其基類(lèi)類(lèi)型對(duì)象的 protected 成員。

1.3 派生類(lèi)
     類(lèi)派生列表指定了一個(gè)或多個(gè)基類(lèi),具有如下形式:
     class classname: access-label base-class 
     這里 access-label 是 public、protected 或 private,base-class 是已定義的類(lèi)的名字,類(lèi)派生列表可以指定多個(gè)基類(lèi)。  
     一旦函數(shù)在基類(lèi)中聲明為虛函數(shù),它就一直為虛函數(shù),派生類(lèi)無(wú)法改變?cè)摵瘮?shù)為虛函數(shù)這一事實(shí)。派生類(lèi)重定義虛函數(shù)時(shí),可以使用 virtual 保留字,也可以不使用。     
(1)派生類(lèi)一般會(huì)重定義所繼承的虛函數(shù)。如果派生類(lèi)沒(méi)有重定義某個(gè)虛函數(shù),則使用基類(lèi)中定義的版本。 
(2)一般情況下,派生類(lèi)中虛函數(shù)的聲明必須與基類(lèi)中的定義方式完全匹配,例外返回對(duì)基類(lèi)型A的引用(或指針)的虛函數(shù)。派生類(lèi)中的虛函數(shù)可以返回類(lèi)A的派生類(lèi)的引用(或指針)。
提示:絕對(duì)不要重新定義繼承而來(lái)的non-virtual函數(shù)
     因?yàn)閚on-virtual函數(shù)是靜態(tài)綁定的。一個(gè)子類(lèi)對(duì)象綁定到一個(gè)父類(lèi)指針,另一個(gè)子類(lèi)對(duì)象綁定到一個(gè)子類(lèi)指針,通過(guò)父類(lèi)指針調(diào)用該函數(shù),調(diào)用的是父類(lèi)的該函數(shù),而不是子類(lèi)的函數(shù)。例如:
class Base
{
public:
     void FuncTest()
     {
          std::cout << "Base" << std::endl;
     }
};
 
class Derived: public Base
{
public:
     void FuncTest()
     {
          std::cout << "Derived" << std::endl;
     }
};
Derived d;
Base* pB = &d;
Derived* pD = &d;
d.FuncTest();//輸出“Derived”
pB->FuncTest();//輸出“Base”
pD->FuncTest();//輸出“Derived”
1.4 non-virtual 和  virtual  函數(shù)的調(diào)用
(1) 將基類(lèi)類(lèi)型的引用或指針綁定到派生類(lèi)對(duì)象,如果調(diào)用非虛函數(shù),則無(wú)論實(shí)際對(duì)象是什么類(lèi)型,都執(zhí)行基類(lèi)類(lèi)型所定義的函數(shù)。
class Base
{
public:
void FuncTest()
{
     std::cout << "Base" << std::endl;
}
};
 
class Derived: public Base
{
public:
};
 
Derived d;
Base* pB = &d;
pB->VirtFunc();//輸出“Base”
(2)將基類(lèi)類(lèi)型的引用或指針綁定到派生類(lèi)對(duì)象,如果調(diào)用虛函數(shù),則直到運(yùn)行時(shí)才能確定調(diào)用哪個(gè)函數(shù),運(yùn)行的虛函數(shù)是引用所綁定的或指針?biāo)赶虻膶?duì)象所屬類(lèi)型定義的版本。
class Base
{
public:
     virtual void VirtFunc()
     {
          std::cout << "Base" << std::endl;
     }
};
 
class Derived: public Base
{
public:
     void VirtFunc()
     {
          std::cout << "Derived" << std::endl;
     }
};
Derived d;
Base* pB = &d;
Derived* pD = &d;
pB->VirtFunc();//輸出“Derived”
pD->VirtFunc();//輸出“Derived”
1.5 虛函數(shù)與默認(rèn)實(shí)參 
     虛函數(shù)也可以有默認(rèn)實(shí)參。如果一個(gè)調(diào)用省略了具有默認(rèn)值的實(shí)參,則所用的值由調(diào)用該函數(shù)的類(lèi)型定義,與對(duì)象的動(dòng)態(tài)類(lèi)型無(wú)關(guān)。通過(guò)基類(lèi)的引用或指針調(diào)用虛函數(shù)時(shí),默認(rèn)實(shí)參為在基類(lèi)虛函數(shù)聲明中指定的值,如果通過(guò)派生類(lèi)的指針或引用調(diào)用虛函數(shù),則默認(rèn)實(shí)參是在派生類(lèi)的版本中聲明的值。
提示: 絕不重新定義繼承而來(lái)virtual函數(shù)的缺省參數(shù)值
     不要重新定義繼承而來(lái)的non-virtual函數(shù),但是可以重新定義一個(gè)繼承而來(lái)的virtual函數(shù)。
     virtual函數(shù)是動(dòng)態(tài)綁定,而該函數(shù)的缺省參數(shù)值卻是靜態(tài)綁定。C++這么做的就是為了提高運(yùn)行期效率。
     如果子類(lèi)重新定義了繼承而來(lái)的virtual函數(shù)的缺省參數(shù)值,那么使用父類(lèi)指針指向子類(lèi)對(duì)象,然后使用父類(lèi)指針來(lái)調(diào)用該函數(shù),所使用的默認(rèn)參數(shù)仍然是從父類(lèi)繼承而來(lái),而非子類(lèi)重新定義定義的。例如:
class Base
{
public:
     virtual void VirtFunc(string sMsg = "Base")
     {
          cout << sMsg << endl;
     }
};
class Derived:public Base
{
public:
     void VirtFunc(string sMsg = "Derived")
     {
          cout << sMsg << endl;
     }
};
Derived d;
d.VirtFunc();//輸出"Derived"
Base* pD = &d;
pD->VirtFunc();//輸出"Base",而不是"Derived"
     為了避免出現(xiàn)上面這種情況,必須將子類(lèi)中繼承而來(lái)的virtual函數(shù)設(shè)計(jì)的跟父類(lèi)一樣,也就是有同樣的缺省參數(shù)值。如果父類(lèi)修改了,子類(lèi)也必須跟著同樣修改。
     替換的設(shè)計(jì)方案是:設(shè)計(jì)一個(gè) public non-virtual函數(shù)(帶有默認(rèn)參數(shù)值)來(lái)調(diào)用private virtual函數(shù)(不帶默認(rèn)參數(shù)值)。public non-virtual函數(shù)在子類(lèi)中不能重新定義,但是private virtual函數(shù)可以在子類(lèi)中重新定義。
class Base
{
public:
     void Func(string sMsg = "Base")
     {
          VirtFunc(sMsg);
     }
private:
     virtual void VirtFunc(string sMsg )
     {
          cout << sMsg << endl;
     }
};
 
class Derived:public Base
{
private:
     virtual void VirtFunc(string sMsg)
     {
          cout << sMsg << endl;
     }
};
 
D d;
d.Func();//輸出"Base"
B* pD = &d;
pD->mf();//輸出"Base"
1.6 友元關(guān)系與繼承
     友元關(guān)系不能繼承:
(1)基類(lèi)的友元對(duì)派生類(lèi)的成員沒(méi)有特殊訪問(wèn)權(quán)限。
(2)友元類(lèi)的派生類(lèi)不能訪問(wèn)授予友元關(guān)系的類(lèi)。

1.7 繼承與靜態(tài)成員
     如果基類(lèi)定義 static 成員,則整個(gè)繼承層次中只有一個(gè)這樣的成員。無(wú)論從基類(lèi)派生出多少個(gè)派生類(lèi),每個(gè) static 成員只有一個(gè)實(shí)例。
     static 成員遵循常規(guī)訪問(wèn)控制:如果成員在基類(lèi)中為 private,則派生類(lèi)不能訪問(wèn)它。
     如果可以訪問(wèn)成員,則既可以通過(guò)基類(lèi)訪問(wèn) static 成員,也可以通過(guò)派生類(lèi)訪問(wèn) static 成員。一般而言,既可以使用作用域操作符也可以使用點(diǎn)或箭頭成員訪問(wèn)操作符。 

2 轉(zhuǎn)換和繼承
2.1 派生類(lèi)到基類(lèi)的轉(zhuǎn)換
(1)指針或引用
     派生類(lèi)型引用到基類(lèi)類(lèi)型引用
     派生類(lèi)型指針到基類(lèi)類(lèi)型指針。
     反之是不行的。
(2)對(duì)象
     一般可以使用派生類(lèi)型的對(duì)象對(duì)基類(lèi)類(lèi)型的對(duì)象進(jìn)行初始化或賦值,但沒(méi)有從派生類(lèi)型對(duì)象到基類(lèi)類(lèi)型對(duì)象的直接轉(zhuǎn)換,編譯器不會(huì)自動(dòng)將派生類(lèi)型對(duì)象轉(zhuǎn)換為基類(lèi)類(lèi)型對(duì)象。
 
3 構(gòu)造函數(shù)和復(fù)制控制
3.1派生類(lèi)構(gòu)造函數(shù)
     構(gòu)造函數(shù)和復(fù)制控制成員不能繼承,每個(gè)類(lèi)定義自己的構(gòu)造函數(shù)和復(fù)制控制成員。像任何類(lèi)一樣,如果類(lèi)不定義自己的默認(rèn)構(gòu)造函數(shù)和復(fù)制控制成員,就將使用合成版本。
     派生類(lèi)的合成默認(rèn)構(gòu)造函數(shù),除了初始化派生類(lèi)的數(shù)據(jù)成員之外,它還初始化派生類(lèi)對(duì)象的基類(lèi)部分?;?lèi)部分由基類(lèi)的默認(rèn)構(gòu)造函數(shù)初始化。
     派生類(lèi)構(gòu)造函數(shù)的初始化列表只能初始化派生類(lèi)的成員,不能直接初始化繼承成員。派生類(lèi)構(gòu)造函數(shù)只能通過(guò)將基類(lèi)包含在構(gòu)造函數(shù)初始化列表中來(lái)間接初始化繼承成員。
class People
{
public:
     People(std::string s1, int i1) : name("s1"),age(i1)
     {
     }
private:
     std::string name;
     int age;
};
 
class Student: public People
{
public:
     Student(std::string s1, int i1,std::string s2) : uniName("s2"),People(s1,i1)
     {
     }
private:
     std::string uniName;//學(xué)校名稱(chēng)
};
     構(gòu)造函數(shù)初始化列表為類(lèi)的基類(lèi)和成員提供初始值,它并不指定初始化的執(zhí)行次序。首先初始化基類(lèi),然后根據(jù)聲明次序初始化派生類(lèi)的成員。
     一個(gè)類(lèi)只能初始化自己的直接基類(lèi)(通過(guò)將基類(lèi)包含在構(gòu)造函數(shù)初始化列表中來(lái)間接初始化基類(lèi))。

3.2 復(fù)制控制和繼承
     只包含類(lèi)類(lèi)型或內(nèi)置類(lèi)型數(shù)據(jù)成員、不含指針的類(lèi)一般可以使用合成操作。
     具有指針成員的類(lèi)一般需要定義自己的復(fù)制控制來(lái)管理這些成員。   
(1) 派生類(lèi)的復(fù)制構(gòu)造函數(shù)
     如果派生類(lèi)定義了自己的復(fù)制構(gòu)造函數(shù),該復(fù)制構(gòu)造函數(shù)一般應(yīng)顯式使用基類(lèi)復(fù)制構(gòu)造函數(shù)初始化對(duì)象的基類(lèi)部分:
class Base { /* ... */ };
class Derived: public Base
{
public:
         Derived(const Derived& d):Base(d) { /*... */ }
}; 
(2)派生類(lèi)賦值操作符
     賦值操作符通常與復(fù)制構(gòu)造函數(shù)類(lèi)似:如果派生類(lèi)定義了自己的賦值操作符,則該操作符必須對(duì)基類(lèi)部分進(jìn)行顯式賦值。
//Base::operator=(const Base&)
Derived &Derived::operator=(const Derived &rhs)
{
        if (this != &rhs) //防止給自己賦值
        {
            Base::operator=(rhs); // 調(diào)用 Base 類(lèi)的賦值操作符給基類(lèi)部分賦值
             ……//為派生類(lèi)Derived 的成員賦值
        }
        return *this;
(3)派生類(lèi)析構(gòu)函數(shù)
     派生類(lèi)析構(gòu)函數(shù)不負(fù)責(zé)撤銷(xiāo)基類(lèi)對(duì)象的成員。每個(gè)析構(gòu)函數(shù)只負(fù)責(zé)清除自己的成員。
class Derived: public Base
{
public:
    ~Derived()    {
/*... */}
};
(4)虛析構(gòu)函數(shù)
     如果層次中基類(lèi)的析構(gòu)函數(shù)為虛函數(shù),則派生類(lèi)析構(gòu)函數(shù)也將是虛函數(shù),無(wú)論派生類(lèi)顯式定義析構(gòu)函數(shù)還是使用合成析構(gòu)函數(shù),派生類(lèi)析構(gòu)函數(shù)都是虛函數(shù)。
     建議:即使析構(gòu)函數(shù)沒(méi)有工作要做,繼承層次的根類(lèi)也應(yīng)該定義一個(gè)虛析構(gòu)函數(shù)。
     在復(fù)制控制成員中,只有析構(gòu)函數(shù)應(yīng)定義為虛函數(shù),構(gòu)造函數(shù)不能定義為虛函數(shù)。
建議:為多態(tài)基類(lèi)聲明為virtual析構(gòu)函數(shù)
     父類(lèi)指針指向子類(lèi)對(duì)象,delete父類(lèi)指針時(shí),如果父類(lèi)含有non-virtual析構(gòu)函數(shù),則只有繼承自父類(lèi)的部分被銷(xiāo)毀,而子類(lèi)非繼承的部分沒(méi)有被銷(xiāo)毀,也就是說(shuō)子類(lèi)對(duì)象被部分銷(xiāo)毀。解決的辦法是,將父類(lèi)的析構(gòu)函數(shù)定義為virtual析構(gòu)函數(shù)。
class Base
{
public:
     Base()
     {
          // std::cout << "Base的構(gòu)造函數(shù)" << std::endl;
     }
 
     ~Base()
     {
          std::cout << "Base的析構(gòu)函數(shù)" << std::endl;
     }
};
 
 
class Derived : public Base
{
public:
     Derived()
     {
          // std::cout << "Derived的構(gòu)造函數(shù)" << std::endl;
     }
 
     ~Derived()
     {
          std::cout << "Derived的析構(gòu)函數(shù)" << std::endl;
     }
};
Base* pB = new Derived;
delete pB;//顯示“Base的析構(gòu)函數(shù)”
如果把Base的析構(gòu)函數(shù)前面添加virtual,則上面結(jié)果輸出:
Derived的析構(gòu)函數(shù)
Base的析構(gòu)函數(shù)
注意:
     任何class只要帶有virtual函數(shù),幾乎確定應(yīng)該也有一個(gè)virtual析構(gòu)函數(shù)。一般的,基類(lèi)應(yīng)該含有virtual析構(gòu)函數(shù)?;?lèi)定義了virtual關(guān)鍵字,子類(lèi)就不用添加該關(guān)鍵字了。
     如果class不含有virtual函數(shù),通常表示它并不打算被用作一個(gè)基類(lèi),所以就不應(yīng)該將析構(gòu)函數(shù)定義為virtual的。
 
4 繼承情況下的類(lèi)作用域
4.1 名字沖突與繼承
     與基類(lèi)成員同名的派生類(lèi)成員將屏蔽對(duì)基類(lèi)成員的直接訪問(wèn)。
     可以使用作用域操作符訪問(wèn)被屏蔽的基類(lèi)成員:
struct Derived : Base
{
         int get_base_mem() { return Base::mem; }
};

設(shè)計(jì)派生類(lèi)時(shí),只要可能,最好避免與基類(lèi)成員的名字沖突。

4.2 作用域與成員函數(shù)
     在基類(lèi)和派生類(lèi)中使用同一名字的成員函數(shù),其行為與數(shù)據(jù)成員一樣:在派生類(lèi)作用域中派生類(lèi)成員將屏蔽基類(lèi)成員。即使函數(shù)原型不同,基類(lèi)成員也會(huì)被屏蔽。

4.3 重載函數(shù)
     如果派生類(lèi)重定義了重載成員,則通過(guò)派生類(lèi)型只能訪問(wèn)派生類(lèi)中重定義的那些成員。
     如果派生類(lèi)想要通過(guò)自身類(lèi)型來(lái)使用重載的版本,那么派生類(lèi)必須重定義所有的重載版本,但這樣會(huì)繁瑣,可以通過(guò)給重載成員提供using 聲明來(lái)達(dá)到簡(jiǎn)化的目的。
using Base::Func;//注意,將所有基類(lèi)Base中的Func函數(shù)在本類(lèi)中可見(jiàn)。

4.3 名字查找與繼承
(1)首先確定進(jìn)行函數(shù)調(diào)用的對(duì)象、引用或指針的靜態(tài)類(lèi)型。
(2)在該類(lèi)中查找函數(shù),如果找不到,就在直接基類(lèi)中查找,如此循著類(lèi)的繼承鏈往上找,直到找到該函數(shù)或者查找完最后一個(gè)類(lèi)。如果不能在類(lèi)或其相關(guān)基類(lèi)中找到該名字,則調(diào)用是錯(cuò)誤的。
(3)一旦找到了該名字,就進(jìn)行常規(guī)類(lèi)型檢查,查看如果給定找到的定義,該函數(shù)調(diào)用是否合法。
(4)假定函數(shù)調(diào)用合法,編譯器就生成代碼。如果函數(shù)是虛函數(shù)且通過(guò)引用或指針調(diào)用,則編譯器生成代碼以確定根據(jù)對(duì)象的動(dòng)態(tài)類(lèi)型運(yùn)行哪個(gè)函數(shù)版本,否則,編譯器生成代碼直接調(diào)用函數(shù)。

5 純虛函數(shù)
     在函數(shù)形參表后面寫(xiě)上 = 0 以指定純虛函數(shù)。該函數(shù)為后代類(lèi)型提供了可以覆蓋的接口,但是這個(gè)類(lèi)中的版本決不會(huì)調(diào)用。
     含有(或繼承)一個(gè)或多個(gè)純虛函數(shù)的類(lèi)是抽象基類(lèi)。除了作為抽象基類(lèi)的派生類(lèi)的對(duì)象的組成部分,不能創(chuàng)建抽象類(lèi)型的對(duì)象。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類(lèi)似文章 更多