title: c++之繼承
tags:
- 語言工具
- c++
categories: c++
date: 2019-02-22
thumbnail: https://upload-images.jianshu.io/upload_images/16271012-b9d61cc2379c189c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240
繼承
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é)!?。?!