C++面試常見題目一(含答案)

1.Static 作用

  • 1.靜態全局變量:在全局變量前上關鍵字static,該變量就被定義成爲一個靜態全局變量,該變量在全局數據區分配,未被初始化的靜態全局變量會被自動初始化爲0;(而自動變量的初始化是隨機數),靜態全局變量在聲明它的源文件可見,其他源文件不可見(不可調用),即對其他文件隱藏。由於靜態全局變量的隱藏作用,所以其他源文件可以定義名字相同的函數和變量,不會發生衝突
    PS:一般情況下,new,malloc等動態分配產生的動態數據存放在堆區,函數內部的自動變量存放在棧區,且隨着函數的退出而釋放空間。靜態局部變量也放在全局數據區,所以,靜態局部變量不會隨着函數的退出而釋放空間

  • 2.靜態局部變量
    static關鍵字+局部變量=靜態局部變量
    該變量在全局數據區分配內存
    靜態局部變量在程序執行到該對象的聲明處時被首次初始化,以後的函數調用不再進行初始化;如果首次聲明沒有顯式初始化,就會被默認初始化爲0;(因爲全局數據區的0X00),;
    靜態局部變量會一直存在到程序結束,但是定義他的函數或者語句塊結束的時候,作用域就隨之結束。

  • 3.靜態函數
    函數的返回類型前加上static關鍵字,該函數就被定義爲靜態函數
    同樣的,靜態函數只能在定義他的文件中使用,對其他文件不可見,也不可被使用。其他文件可以定義相同名字的函數。

  • 4.靜態數據成員
    類內數據成員的聲明前加上關鍵字static,該數據成員就是類內的靜態數據成員,按照聲明的順序進行初始化,消除時的時候是聲明的發順序,即越先聲明的越晚被消除。
    對於非靜態數據成員,每個類對象都有自己的拷貝。而靜態數據成員被當作是類的成員。無論這個類的對象被定義了多少個,靜態數     據成員在程序中也只有一份拷貝,由該類型的所有對象共享訪問。也就是說,靜態數據成員是該類的所有對象所共有的。對該類的多個對象來說,靜態數據成員只分配一次內存,供所有對象共用。所以,靜態數據成員的值對每個對象都是一樣的,它的值可以更新
    調用方式:<類對象名>.<靜態數據成員名> 或 <類類型名>::<靜態數據成員名>

  • 5.靜態成員函數
    普通函數都含有this指針,通常情況下缺省了。而靜態成員函數由於不是和任何對象聯繫,因此不具備this指針,所以他無法訪問類的非靜態數據成員和非靜態成員函數。
    static函數不能被繼承,只屬於該類。也不能聲明爲虛函數。

2.什麼函數不能成爲虛函數
虛函數通過動態聯編實現了多態
首先,不具備繼承特性 的函數不能成爲虛函數

  • 非成員函數(普通函數)
    普通函數只能重載不能重寫,編譯器會在編譯時綁定函數。
    PS:
    方法重寫(overriding):也叫子類的方法覆蓋父類的方法,要求返回值、方法名和參數都相同。子類拋出的異常不能超過父類相應方法拋出的異常。(子類異常不能超出父類異常);子類方法的的訪問級別不能低於父類相應方法的訪問級別(子類訪問級別不能低於父類訪問級別)
    方法重載(overloading):重載是在同一個類中的兩個或兩個以上的方法,擁有相同的方法名,但是參數卻不相同,方法體也不同,最常見的重載的例子就是類的構造函數。
  • 靜態成員函數
    靜態成員函數對於每個類來說只有一份代碼,所有的對象都共享這一份代碼,他也沒有要動態邦定的必要性
  • 內聯函數
    內聯函數在編譯時則被替換展開,虛函數在運行時才能動態的綁定函數。
  • 友元函數
    C++不支持友元函數被繼承。
  • 構造函數
    構造函數不能被繼承,構造函數就是爲了創建初始化對象存在的,對象不存在實現多態就不可能了。

虛函數和純虛函數的區別
答:虛函數在基類中有定義,即使爲空
純虛函數在基類中沒有定義,必須在子類中加以實現。
PS:純虛函數:virtual 函數名()=0;使用純虛函數的情況:1. 當想在基類中抽象出一個方法,且該基類只能被繼承,而不能實例化2.這個方法必須在子類中實現
3.內聯函數(inline)
內聯函數:內聯函數是指那些定義在類體內的成員函數,即該函數的函數體放在類體內。
1.在C++中,有一些函數不斷頻繁的被調用,即不斷入函數棧,會造成棧空間或者棧內存的大量消耗
在系統下,棧空間是有限的,假如頻繁大量的使用就會造成因棧空間不足所造成的程式出錯的問題,函數的死循環遞歸調用的最終結果就是導致棧內存空間枯竭。

調用宏比調用一個函數更有效率,因爲宏只是在預處理的時候將代碼展開,不需要額外的空間和時間方面的開銷。
宏的缺點:
1.不能訪問對象的私有成員
2.容易產生二義性

inline和宏的區別
內聯函數和宏的區別在於,宏是由預處理器對宏進行替代,而內聯函數是通過編譯器控制來實現的。而且內聯函數是真正的函數,只是在需要用到的時候,內聯函數像宏一樣的展開,所以取消了函數的參數壓棧,減少了調用的開銷

inline的用法

  1. inline關鍵字必須和函數體在一起,單純的inline和函數頭聲明在一起是沒有效果的。
    實現方法
inline 函數名()
{
函數實現
}

或者

inline 函數名();
巴拉巴拉一些別的函數啊什麼的
inline 函數名()
{
函數實現;
}

inline函數的使用限制
inline只適合涵數體內代碼簡單的函數數使用,不能包含複雜的結構控制語句例如while、switch,並且內聯函數本身不能是直接遞歸函數(自己內部還調用自己的函數)。

內聯是以代碼複製爲代價,省去了函數調用的代價,從而提高函數的執行效率。
如果執行函數體內的代碼的時間,相比函數調用的開銷較大,那麼內聯的收益就很少,而且,每一處內斂的調用都要複製代碼,使得程序的總代碼量增大,消耗更多地內存空間。
所以,以下情況不使用內聯
1.函數體內代碼較長
2.函數體內處出現循環,那麼執行函數體內代碼的時間要比函數調用的開銷大

總結:內聯函數最好定義在頭文件中,就不用每個文件實現一次。
如果每個文件實現一次的話,最好保證每個定義是一樣的,否則會引起未定義的錯誤。

4.C++特性
封裝:封裝是實現面向對象程序設計的第一步,封裝就是將數據或函數等集合在一個個的單元中(我們稱之爲類)。封裝的意義在於保護或者防止代碼(數據)被我們無意中破壞。

繼承:繼承主要實現重用代碼,節省開發時間。子類可以繼承父類的一些東西。

多態:是指相同的操作或函數、過程可作用於多種類型的對象上並獲得不同的結果。不同的對象,收到同一消息可以產生不同的結果,這種現象稱爲多態。

多態

定義: “一個接口,多種方法”,程序在運行時才決定調用的函數。
實現: C++多態性主要是通過虛函數實現的,虛函數允許子類重寫override(注意和overload的區別,overload是重載,是允許同名函數的表現,這些函數參數列表/類型不同)。
目的: 封裝可以使得代碼模塊化,繼承可以擴展已存在的代碼,他們的目的都是爲了代碼重用。而多態的目的則是爲了接口重用。爲了類在繼承和派生的時候,保證使用家族中任一類的實例的某一屬性時的正確調用。

5.可不可以用const和static修飾成員函數

const修飾類的成員變量,表示該成員變量不能被修改。
const修飾函數,表示本函數不會修改類內的數據成員。不會調用其他非const成員函數。
const函數只能調用const函數,非const函數可以調用const函數
類外定義的const成員函數,在定義和聲明出都需要const修飾符

6.指針和引用的區別
1.指針是一個實體,需要分配內存空間。引用只是變量的別名,不需要分配內存空間。
2、引用在定義的時候必須進行初始化,並且不能夠改變。指針在定義的時候不一定要初始化,並且指向的空間可變。(注:不能有引用的值不能爲NULL)
3、有多級指針,但是沒有多級引用,只能有一級引用。
4、指針和引用的自增運算結果不一樣。(指針是指向下一個空間,引用時引用的變量值加1)
5、sizeof 引用得到的是所指向的變量(對象)的大小,而sizeof 指針得到的是指針本身的大小。
6、引用訪問一個變量是直接訪問,而指針訪問一個變量是間接訪問

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章