繼承


title: c++之繼承
tags:


繼承

C++派生語法

class Base
{
// ... base class members
};
class Derived: access-specifier Base
{
// ... derived class members
};
其中 access-specifier 可以是 public(這是最常見的,表示派生類是一個(gè)基類)、private 或 protected

下面是一個(gè)簡(jiǎn)單的歷程,用來加深對(duì)繼承的理解。

魚類世界呈現(xiàn)的一種簡(jiǎn)單的繼承層次結(jié)構(gòu)

 #include <iostream> 
using namespace std; 
class Fish 
{ 
public: 
bool isFreshWaterFish; 
void Swim() 
{ 
if (isFreshWaterFish) 
cout << "Swims in lake" << endl; 
else 
cout << "Swims in sea" << endl; 
} 
}; 

class Tuna: public Fish 
{ 
public: 
Tuna() 
{ 
isFreshWaterFish = false;
} 
}; 

class Carp: public Fish 
{ 
public: 
Carp() 
{ 
isFreshWaterFish = true; 
} 
}; 

int main() 
{ 
Carp myLunch; 
Tuna myDinner; 

cout << "About my food:" << endl; 

cout << "Lunch: "; 
myLunch.Swim(); 

cout << "Dinner: "; 
myDinner.Swim(); 

return 0; 
} 
輸出:
About my food: 
Lunch: Swims in lake 
Dinner: Swims in sea

訪問限定符 protected

public 和 private 一樣,protected 也是一個(gè)訪問限定符。將屬性聲明為 protected 的時(shí),
相當(dāng)于允許派生類和友元類訪問它,但禁止在繼承層次結(jié)構(gòu)外部(包括 main( ))訪問它.

一種更好的 Fish 類設(shè)計(jì),它使用關(guān)鍵字 protected 將成員屬性只暴露給派生類
#include <iostream> 
 using namespace std; 

class Fish 
   { 
    protected: 
       bool isFreshWaterFish;  
    public: 
         void Swim() 
   { 
      if (isFreshWaterFish) 
     cout << "Swims in lake" << endl; 
   else 
      cout << "Swims in sea" << endl; 
 } 
    }; 

 class Tuna: public Fish
  { 
public: 
    Tuna() 
      { 
 isFreshWaterFish = false; // set protected member in base 
     }
  }; 

class Carp: public Fish 
 { 
public: 
    Carp() 
   { 
  isFreshWaterFish = false; 
   } 
 }; 

int main() 
{
 Carp myLunch; 
 Tuna myDinner; 
 cout << "About my food" << endl;  
 cout << "Lunch: "; 
 myLunch.Swim();  
 cout << "Dinner: "; 
 myDinner.Swim(); 
 return 0; 
    } 
}

輸出:
About my food 
Lunch: Swims in lake 
Dinner: Swims in sea 


## 基類初始化—向基類傳遞參數(shù)
 結(jié)構(gòu)如下:
class Base 
{ 
public: 
 Base(int someNumber) // overloaded constructor 
 { 
 // Use someNumber 
 } 
}; 
Class Derived: public Base 
{ 
public: 
 Derived(): Base(25) // instantiate Base with argument 25 
 { 
 // derived class constructor code 
 } 
}; 

下面看一下具體例子;

#include <iostream> 
  using namespace std;  
 class Fish 
     { 
  protected: 
           bool isFreshWaterFish; // accessible only to derived classes 
 public: 
          Fish(bool isFreshWater) : isFreshWaterFish(isFreshWater)
         {
         } 
 void Swim() 
     { 
      if (isFreshWaterFish) 
         cout << "Swims in lake" << endl; 
   else 
         cout << "Swims in sea" << endl; 
    } 
  }; 

class Tuna: public Fish 
 { 
 public: 
        Tuna(): Fish(false) 
          {
           }
 }; 

class Carp: public Fish 
 { 
public: 
         Carp(): Fish(true)
          {
          } 
  }; 
 
 int main() 
 { 
       Carp myLunch; 
       Tuna myDinner; 
 cout << "About my food" << endl; 
cout << "Lunch: "; 
 myLunch.Swim(); 
cout << "Dinner: "; 
myDinner.Swim(); 
 return 0; 
} 

輸出:
About my food 
Lunch: Swims in lake 
Dinner: Swims in sea

在派生類中覆蓋基類的方法

如果派生類實(shí)現(xiàn)了從基類繼承的函數(shù),且返回值和特征標(biāo)相同,就相當(dāng)于覆蓋了基類的這個(gè)方法,
如下面的代碼所示:
class Base
{
public:
void DoSomething()
{
// implementation code… Does something
}
};
class Derived:public Base
{
public:
void DoSomething()
{
// implementation code… Does something else
}
};

派生類 Tuna 和 Carp 覆蓋了基類 Fish 的方法 Swim( ) 
 #include <iostream> 
using namespace std; 

class Fish 
        { 
private: 
        bool isFreshWaterFish; 
 public: 
        Fish(bool isFreshWater) 
         : isFreshWaterFish(isFreshWater)
          {
          } 
 void Swim() 
 { 
if (isFreshWaterFish) 
 cout << "Swims in lake" << endl; 
       else 
 cout << "Swims in sea" << endl; 
 } 
          }; 

 class Tuna: public Fish 
 { 
public: 
       Tuna()
         : Fish(false) 
{
} 
 void Swim() 
{ 
 cout << "Tuna swims real fast" << endl; 
   } 
    }; 

 class Carp: public Fish 
{ 
 public: 
        Carp()
              : Fish(true)
              {
              } 
 void Swim() 
  { 
      cout << "Carp swims real slow" << endl; 
   } 
 }; 

int main() 
 { 
Carp myLunch; 
Tuna myDinner; 
cout << "About my food" << endl; 
cout << "Lunch: "; 
myLunch.Swim(); 
cout << "Dinner: "; 
 myDinner.Swim(); 
return 0; 
 } 

輸出:
About my food 
Lunch: Carp swims real slow 
Dinner: Tuna swims real fast 

分析: myLunch.Swim( )調(diào)用的是 Carp::Swim( )。同樣,myDinner.Swim( )調(diào)用的是Tuna::Swim( )。換句話說,基類 Fish 中 Swim( )被派生類 Tuna 和 Carp 類中的 Swim( )覆蓋了。要調(diào)用 Fish::Swim( ),只能在 main( )中使用作用域解析運(yùn)算符顯式地調(diào)用它。
即:如果要在 main( )中調(diào)用 Fish::Swim( ),需要使用作用域解析運(yùn)算符(::),如
下所示:
myDinner.Fish::Swim();

在派生類中調(diào)用基類的方法

如果要在 Tuna::Swim( )
和 Carp::Swim( )的實(shí)現(xiàn)中重用 Fish::Swim( )的通用實(shí)現(xiàn),可使用作用域解析運(yùn)算符(::),如下面的代
碼所示:
class Carp: public Fish
{
public:
Carp(): Fish(true) {}
void Swim()
{
cout << "Carp swims real slow" << endl;
Fish::Swim(); // invoke base class function using operator::
}
};

具體應(yīng)用

在基類方法和 main( )中,使用作用域解析運(yùn)算符(::)來調(diào)用基類方法

 #include <iostream> 
using namespace std; 
 class Fish 
{ 
 private: 
 bool isFreshWaterFish;  
public: 
 Fish(bool isFreshWater) : isFreshWaterFish(isFreshWater){} 
void Swim() 
{ 
 if (isFreshWaterFish) 
 cout << "Swims in lake" << endl; 
 else 
cout << "Swims in sea" << endl; 
 } 
 }; 
 class Tuna: public Fish 
 { 
 public: 
 Tuna(): Fish(false) {} 
 void Swim() 
 { 
 cout << "Tuna swims real fast" << endl; 
 } 
 }; 
 class Carp: public Fish 
 { 
 public: 
 Carp(): Fish(true) {} 
 void Swim() 
 { 
 cout << "Carp swims real slow" << endl; 
Fish::Swim(); 
 } 
 }; 
 int main() 
 { 
Carp myLunch; 
 Tuna myDinner; 
 cout << "About my food" << endl;  
 cout << "Lunch: "; 
 myLunch.Swim(); 
 cout << "Dinner: "; 
 myDinner.Fish::Swim(); 
 return 0; 
 } 
輸出:
About my food 
Lunch: Carp swims real slow 
Swims in lake 
Dinner: Swims in sea 

構(gòu)造順序

基類對(duì)象在派生類對(duì)象之前被實(shí)例化。首先構(gòu)造 Tuna 對(duì)象的Fish 部分,這樣實(shí)例化 Tuna 部分時(shí),成員屬性(具體地說是 Fish 的保護(hù)和公有屬性)已準(zhǔn)備就緒,可以使用了。實(shí)例化 Fish 部分和 Tuna 部分時(shí),先實(shí)例化成員屬性(如 Fish::isFreshWaterFish),再調(diào)用構(gòu)造函數(shù),確保成員屬性準(zhǔn)備就緒,可供構(gòu)造函數(shù)使用。這也適用于 Tuna::Tuna( )。
析構(gòu)順序與此相反

私有繼承

格式如下:
class Base
{
// ... base class members and methods
};
class Derived: private Base // private inheritance
{
// ... derived class members and methods
};

私有繼承意味著在派生類的實(shí)例中,基類的所有公有成員和方法都是私有的—不能從外部訪問。
換句話說,即便是 Base 類的公有成員和方法,也只能被 Derived 類使用,而無法通過 Derived 實(shí)例來
使用它們。
在公有繼承中,,可在 main( )中通過 Tuna 實(shí)例調(diào)用 Fish::Swim( ),因?yàn)?Fish::Swim( )是個(gè)公有方法,且 Tuna 類是以公有方式從 Fish 類派生而來的。而在私有繼承中無法實(shí)現(xiàn)。私有繼承使得只有子類才能使用基類的屬性和方法,因此也被稱為 has-a 關(guān)系。
比如由發(fā)動(dòng)機(jī)派生汽車,由小到大的派生。

實(shí)例

Car 類以私有方式繼承 Motor 類
 0: #include <iostream> 
 using namespace std; 
 class Motor 
 { 
 public: 
 void SwitchIgnition() 
   { 
 cout << "Ignition ON" << endl; 
  } 
 void PumpFuel() 
   { 
 cout << "Fuel in cylinders" << endl; 
   } 
 void FireCylinders() 
 { 
 cout << "Vroooom" << endl; 
 } 
           };  

class Car:private Motor // private inheritance 
 { 
 public: 
 void Move() 
{ 
   SwitchIgnition(); 
   PumpFuel(); 
   FireCylinders(); 
    } 
           }; 

 int main() 
 { 
    Car myDreamCar; 
    myDreamCar.Move(); 
 return 0; 
 } 

輸出:
Ignition ON 
Fuel in cylinders 
Vroooom 

保護(hù)繼承

結(jié)構(gòu)如下:
class Base
{
// ... base class members and methods
};
class Derived: protected Base // protected inheritance
{
// ... derived class members and methods
};
特征:
? 它也表示 has-a 關(guān)系;
? 它也讓派生類能夠訪問基類的所有公有和保護(hù)成員;
? 在繼承層次結(jié)構(gòu)外面,也不能通過派生類實(shí)例訪問基類的公有成員。
隨著繼承層次結(jié)構(gòu)的加深,保護(hù)繼承將與私有繼承有些不同:
class Derived2: protected Derived
{
// can access public & protected members of Base
}
在保護(hù)繼承層次結(jié)構(gòu)中,子類的子類(即 Derived2)能夠訪問 Base 類的公有和保護(hù)成員

實(shí)例理解

 RaceCar 類以保護(hù)方式繼承了 Car 類,而 Car 類以保護(hù)方式繼承了 Motor 類
#include <iostream> 
 using namespace std; 
 class Motor 
 { 
 public: 
 void SwitchIgnition() 
 { 
 cout << "Ignition ON" << endl; 
 } 
void PumpFuel() 
 { 
 cout << "Fuel in cylinders" << endl; 
 } 
void FireCylinders() 
 { 
cout << "Vroooom" << endl; 
 } 
 }; 
 class Car:protected Motor 
{ 
public: 
 void Move() 
 { 
 SwitchIgnition(); 
PumpFuel(); 
FireCylinders(); 
 } 
 };  
class RaceCar:protected Car 
 { 
public: 
 void Move() 
 { 
SwitchIgnition(); 
 PumpFuel(); 
 FireCylinders();
 FireCylinders(); 
 FireCylinders(); 
 } 
 }; 
 int main() 
 { 
 RaceCar myDreamCar;
 myDreamCar.Move();  
return 0; 
 } 

輸出:
Ignition ON 
Fuel in cylinders 
Vroooom 
Vroooom 
Vroooom 

多繼承

class Derived: access-specifier Base1, access-specifier Base2
{
// class members
};

使用 final 禁止繼承

被聲明為 final 的類不能用作基類。


文章依據(jù)21天學(xué)通C++第八版,純屬小白自學(xué)!?。?!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容