天天看點

C++基礎

C++基礎

public和protected和private三種繼承有什麼差別

三種繼承方式對于子類來說沒有任何差別,但是對于子類的執行個體化對象來講有差別。但是隻分為兩種,public一種和protected,private一種。後者會使子類的執行個體化對象無法通路到基類的public成員。

protected和private會影響到子類的子類,即影響到孫子類。如果是protected繼承,那麼結果和public繼承一樣,public和protected屬性都能夠通路,如果是private繼承,那麼孫子類無法通路到基類的所有屬性,因為對他來說這些屬性在繼承至子類的時候已經變成了private

public繼承可以視為是is-a關系,而private繼承類似複合(has-a),但是又比複合更第一層

C++的記憶體結構使怎樣的

  • 堆區:編譯器自動配置設定釋放的區域,局部變量和函數參數就儲存在堆區,離開作用域自動釋放
  • 棧區:程式員手動申請的區域,比如new和malloc
  • 全局區:全局變量和靜态變量存放的區,程式結束後才釋放
  • 代碼區

New和Malloc的差別

最基本的,new是C++風格的記憶體申請,它是經過包裝的,比malloc更安全。

  • 使用new不需要指定需要配置設定多少空間,而malloc需要。同時new傳回的是申請的對象的指針,而malloc傳回的是void*,需要使用者自行轉換,這是不安全的,而new是類型安全的。如果new配置設定失敗了會抛出bad_alloc異常,而malloc失敗了會傳回NULL。如果new的是一個對象的話那麼他還會調用到它的構造函數

調用new/delete的過程

首先new會調用operator new來配置設定記憶體,然後會使用static_cast進行轉型,最後利用轉型後的指針來調用一波構造函數

operator new是一個可重載的函數,他的内部會調用malloc,若失敗了抛出異常,成功了則配置設定一個指定的記憶體空間,然後傳回一個空指針

delete的話會先執行析構函數,然後再執行operator delete

指針和引用的差別

指針使用的時候可以不需要初始化嗎,引用需要初始化

指針在運作過程中可能會成為野指針或者空指針

引用的本質可以看作是指針常量,因為它引用的目标不能更改,但是可以

static_cast和dynamic_cast的差別

static_cast可以說是适用于C風格的轉換,比如說double到float,轉換int到char,子類轉父類等等

dynamic_cast用于多态類型的轉換,同時它自帶IDE檢查,隻能用于指針和引用的轉換

dynamic_cast自帶類型檢查,對于指針類型若失敗會傳回nullptr,對于引用類型失敗會抛出bad_cast異常

兩者都在編譯器層面都不支援無效的類型轉換,且dynamic_cast在轉換失敗時會傳回一個nullptr,而static_cast不會,是以static_cast是不安全的。

reinterpret_cast用于指針類型的轉換

const_cast用于消除const限定符

memcpy和strcpy的差別?

  • mencpy能拷貝任意類型的資料,而strcpy隻能拷貝字元串
  • mencpy需要顯示指定拷貝的長度,而strcpy不需要,當他遇到/0的時候會自動停止,這種就可能會導緻記憶體溢出

編譯期多态和運作期多态

通俗的來講這兩者的差別就是:應該調用哪一個重載?和 應該綁定哪一個虛函數?

編譯期多态是指不同的模闆參數具現化導緻調用不同的重載函數,STL就是靜态多态一個應用的例子,泛型程式設計。效率較高,但是調試困難

  • 函數重載
  • 函數模闆

運作期多态指利用查虛函數表實作的基類對象調用派生類的成員函數,運作時動态綁定,效率較低

  • 虛函數表

如果一個類至少一個虛函數的話,那麼這個類就擁有一張虛函數表,如果他有子類,那麼子類也會有一張虛函數表。

虛函數表可以看作是一個存放虛函數指針的數組

每個類的執行個體化對象都會有一個指向該虛函數表的指針,虛函數表的指針是在類的構造函數中初始化的

函數簽名

函數名 函數參數 函數參數順序 所在的類 所在的名稱空間

C語言的函數簽名不包含函數參數和參數順序,是以C語言沒有函數重載

static

靜态全局變量,靜态全局函數,它們都是單檔案使用的

靜态局部變量,重複聲明不會覆寫其值

靜态成員變量和靜态成員函數:聲明周期比類長,每個類有一份,而不是每個類執行個體,每個類執行個體共享這一份。類内靜态成員函數可以通路其他非靜态成員函數和變量,但是類内非靜态成員函數不能通路類内靜态成員變量和函數

const

修飾變量

修飾指針:頂層指針(指針常量),指向的方向不能更改。底層指針(常量指針),指向的值不能更改

修飾函數參數

修飾函數傳回值

修飾函數——常函數

inline

聲明和定義都在類内的成員函數預設是inline

内聯函數在調用時與宏調用一樣展開,不需要函數調用時參數的壓棧操作,減少了調用開銷

struct和class

預設成員通路權限,public和private;預設繼承權限,public和private

class可用于模闆中替代typename

其實作版本的C++中struct和class已經幾乎一緻了,說使用差別的話那應該是為了相容C語言。struct可以成為一個單純的資料集合,或者說是POD,而類要擔負的就更多,比如做資料處理等等

Union

union中的資料類型是不允許具有構造函數的,可以允許POD的存在。Union中的資料存在于同一片記憶體中,至于提取出來什麼值看你使用什麼方法去解釋它

union U
{
    int a;
    char c;
};
           
int main()
{
    U u;
    u.c = '1';
    cout << u.c << endl;	// '1'
    u.a = 100;
    cout << u.c << endl;	// 'd'
}
           

友元

友元函數

友元全局函數

class A
{
    friend void globalVisit();
    int data = 100;
    int showData() { return data;  }
};


void globalVisit()
{
    A a;
    a.showData();
}
           

其實這個函數寫在類A中也是可以的,但是它同樣不能直接通路A對象的

private

protected

對象

void globalVisit()
{
    // 不行
    cout << data << endl;
}
           

友元成員函數

首先B中被當成朋友的函數得是

public

的,其次該函數需要在類A聲明後再實作

class B
{
public:
    void visitFriend();
};

class A
{
    friend void B::visitFriend();
    int data = 100;
    int showData() { return data;  }
};

void B::visitFriend()
{
    A a;
    a.showData();
}
           

友元類

順序需要是先朋友再主人

class B
{
    void visitFriend()
    {
        A a;
        a.showData();
    }
};

class A
{
    friend B;
    int data;
    int showData() { return data;  }
};
           

記憶體對齊

// 大小是16
union U
{
    int arr[3];
    double d;
};

// 大小是24
struct S1
{
    int arr[3];
    double d;
};

// 大小是12
struct S2
{
    char c1;
    int i;
    char c2;
};
           

強枚舉類型

enum class my_enum : unsigned int
{
    value1,     // 0
    value2,     // 1
    value3 = 100,
    value4 = 200,
    value5,     // 201
};
           

繼續閱讀