多繼承1-虛函數
如果子類繼承的多個父類都有虛函數, 那麼子類對象就會產生對應的多張虛表.
同名函數
同名成員變量
多繼承2-菱形繼承
菱形繼承帶來的問題:
最底下子類從基類繼承的成員變量冗餘, 重複(有兩個age, 內存是兩份, 從語法上正確, 但不合理)
最底下子類無法訪問基類的成員, 有二義性.
多繼承3-虛繼承
虛繼承可以解決菱形繼承帶來的問題
Student和Worker共用一個age, 共享
從虛基類裏面搞過來的成員變量都放到最後面, 這個對象會多出4個字節, 存放虛表指針, 20和12是拿來尋找age的, 拿來定位虛基類的成員變量在哪裏, 因爲age是共享的, 所以就要保證不管是從Worker這個類開始找還是從Student這個類開始找, 都能找到age.
Person類被稱爲虛基類
靜態成員(static)
◼ 靜態成員:被static修飾的成員變量\函數
□可以通過對象(對象.靜態成員)、對象指針(對象指針->靜態成員)、類訪問(類名::靜態成員)
◼ 靜態成員變量
□ 存儲在數據段(全局區,類似於全局變量),整個程序運行過程中只有一份內存, 不在類裏面
□ 對比全局變量,它可以設定訪問權限(public、protected、private),達到局部共享的目的
□ 必須初始化,必須在類外面初始化,初始化時不能帶static,如果類的聲明和實現分離(在實現.cpp中初始化)
◼ 靜態成員函數
□ 內部不能使用this指針(this指針只能用在非靜態成員函數內部)
□ 不能是虛函數(虛函數只能是非靜態成員函數)
□ 內部不能訪問非靜態成員變量\函數,只能訪問靜態成員變量\函數
□ 非靜態成員函數內部可以訪問靜態成員變量\函數
□ 構造函數、析構函數不能是靜態
□ 當聲明和實現分離時,實現部分不能帶static
靜態成員經典應用-單例模式
單例模式:設計模式的一種, 保證某個類永遠只創建一個對象.
1.構造函數\析構函數私有化, 拷貝構造函數私有化, 賦值運算符重載函數私有化.
2.定義一個私有的static成員變量指向唯一的那個單例對象
3.提供一個公共的訪問單例對象的接口.
#include <iostream>
using namespace std;
class Rocket {
private:
Rocket() {}
static Rocket *ms_rocket;
public:
static Rocket *sharedRocket() {
// 這裏要考慮多線程安全
if (ms_rocket == NULL) {
ms_rocket = new Rocket();
}
return ms_rocket;
}
static void deleteRocket() {
// 這裏要考慮多線程安全
if (ms_rocket != NULL) {
delete ms_rocket;
ms_rocket = NULL;
// 防止野指針
}
}
void run() {
cout << "run()" << endl;
}
};
Rocket *Rocket::ms_rocket = NULL;
int main()
{
Rocket *p = Rocket::sharedRocket();
p->run();
p->deleteRocket();
return 0;
}
(1)爲什麼要用指針?
1.在C++開發中, 對象能放堆空間, 儘量放堆空間.
2.對於單例對象, 要考慮內存的靈活使用, 因爲牽扯到內存的分配和銷燬, 所以用堆空間更靈活.
(2)賦值運算符重載函數爲什麼要私有化?
因爲兩個一樣的對象做賦值操作沒有意義.
(3)拷貝構造函數爲什麼要私有化?
因爲如果不寫拷貝構造函數, 還可以通過調用默認的拷貝構造函數去構建對象.如:
Rocket *p1 = Rocket::sharedRocket();
Rocket *p2 = new Rocket(*p1)
其他C++系列文章:
C++知識點總結(基礎語法1-函數重載, 默認參數)
C++知識點總結(基礎語法2-內聯函數, const, 引用)
C++知識點總結(面向對象1-類和對象, this指針, 內存佈局)
C++知識點總結(面向對象2-構造函數, 初始化列表)C++知識點總結(面向對象4-多繼承, 靜態成員static)
C++知識點總結(面向對象5-const成員, 拷貝構造函數)
C++知識點總結(面向對象6-隱式構造, 友元, 內部類, 局部類)
C++知識點總結(其他語法1-運算符重載)
C++知識點總結(其他語法2-模板, 類型轉換, C++11新特性)