一、對比面向過程具有抽象、封裝、繼承和多態的特點:
封裝是將抽象得到的數據和行為相結合,形成了一個有機整體,使得一部分成員充當類與外部的接口,而將其他成員隱藏了起來達到了對成員訪問權限的合理控制,使得不同類之間的影響最小,加強數據安全,簡化編程。
繼承允許在保持原有類特性的基礎上,進行更具體、更詳細的說明,能夠很好反映出特殊概念和一般概念之間的關系,是代碼復用的基礎機制。
多態使得一段程序能夠具有處理多種類型對象的能力,相同的消息在不同的對象下會有不同的動作,增強了編程的靈活性。
二、使用const定義常量與用使用define定義常量相比,有什么優點?
a. const常量有數據類型,而宏常量沒有數據類型。編譯器可以對const常量進行類型安全檢查,而對宏常量只能字符替換
b. 有些集成化的調試工具能對const常量進行調試,對宏常量不能調試
c.const定義的常量在程序運行的過程中只有一份拷貝,而define定義的常量在內存中有若干拷貝。
三、用代碼說明在標准C++中如何進行輸入輸出,並解釋各語句的含義是什么?
cout<<"hello!"<<"world";
cin>>a>>b;
在輸入時,從鍵盤輸入的數據先放在鍵盤緩沖區中,當按回車鍵時,鍵盤緩沖區中的數據輸入到程序中的輸入緩沖區,形成cin流,然后用流提取運算符“>>”從輸入緩沖區中提取數據送給程序中的有關變量。
當用cout和流插入運算符“<<”向顯示器輸出數據時,先將這些數據送到程序中的輸出緩沖區保存,直到緩沖區滿了或遇到endl,就將緩沖區中的全部數據送到顯示器顯示出來。
四、闡述C++中函數三種調用的方式實現機制、特點及其實參、形參的格式,最好用代碼說明。(提示:傳址、傳值、引用傳遞)
在C++中調用函數時有三種參數傳遞方式:
(1)傳值調用;
int main( )
{ void swap(int,int); //函數聲明
int i=3,j=5;
swap(i,j); //調用函數swap
return 0;
} void swap(int a,int b) //企圖通過形參a和b的值互換,實現實參i和j的值互換
{ int temp;
temp=a; //以下3行用來實現a和b的值互換
a=b;
b=temp;
}
(2)傳址調用(傳指針);
用指針類型作為形參的值調用方式,可以通過參數返回修改后的值。
void main( )
{ void swap(int *,int *); int i=3,j=5;
swap(&i,&j); //實參是變量的地址
} void swap(int *p1,int *p2) //形參是指針變量
{ int temp;
temp=*p1; //以下3行用來實現i和j的值互換
*p1=*p2; *p2=temp;
}
(3)引用傳遞;
按引用傳遞,引用實參的引用參數傳遞給函數,而不是進行參數拷貝。引用類型的形參與相應的實參占用相同的內存空間,改變引用類型形參的值,相應實參的值也會隨着變化。
int main( )
{ void swap(int &,int &); int i=3,j=5;
swap(i,j); return 0;
} void swap(int &a,int &b) //形參是引用類型
{ int temp;
temp=a;
a=b;
b=temp;
}
五、什么是類的前向聲明?使用類的前向聲明時,要注意什么?
遇到倆個類相互引用的循環依賴情況
class B; //前向引用聲明
class A//A類的定義
{ public://外部接口
void f(B b);//以B類對象b為形參的成員函數
}; class B//B類的定義
{ public://外部接口
void g(A a);//以A類對象a為形參的成員函數
};
前向引用聲明,是在引用未定義的類之前,聲明該類,使編譯器知道那是一個類名。這樣,當程序中使用這個類名時,編譯器就不會認為是錯誤,而類的完整定義可以在程序的其他地方。
注意:盡管使用了前向引用聲明,但是在提供一個完整的類聲明之前,不能定義該類的對象,也不能在成員函數中使用該類的對象。只能用於定義指針、引用、以及用於函數形參的指針和引用。當你使用前向引用聲明時,你只能使用被聲明的符號,而不能涉及類的任何細節。
六、什么是內聯函數?為什么要使用內聯函數?
在編譯時將所調用函數的代碼直接嵌入到主調函數中,而不是將流程轉出去,這種嵌入到主調函數中的函數成為內聯函數。為了節省參數傳遞、控制轉換等開銷,比如:壓棧、彈棧、保存現場與恢復現場。
操作符new的作用是什么?如何申請單個空間?如何申請動態數組?用new創建一個類的對象時,會發生哪些操作?必要時,請用代碼說明。
作用:在堆中申請一段空間,動態分配內存
申請單個空間int *i = new int;
申請動態數組int *a = new int[10];
new創建類對象需要指針接收,一處初始化,多處使用,作用域是全局,且需要手動釋放空間,在堆中動態分配內存,調用構造函數。
七、操作符delete的作用是什么?如何刪除單個用new申請的空間?如何刪除申請的動態數組?用delete刪除一個類的對象時,會發生哪些操作?必要時,請用代碼說明。
作用:釋放所申請的空間
釋放單個空間delete i;
釋放動態數組delete []a;
釋放在堆中分配的內存,調用析構函數。
八、什么是對象?什么是類?類與對象的關系是什么?
類是邏輯上相關的函數與數據的封裝,它是對問題的抽象描述。
對象是類的某一特定實體。
將整個公司的雇員看成一個類,那么每一個雇員就是該類的一個特定實體,也就是一個對象。
類對象的關系:類是對象的抽象,而對象是類的具體實例。類是抽象的,不占用內存,而對象是具體的,占用存儲空間。類是用於創建對象的藍圖,它是一個定義包括在特定類型的對象中的方法和變量的軟件模板。
九、類中的成員可以用public/protected/private分別進行修飾,這三種成員在什么情況下是可以被訪問的?類中沒有用public/protected/private修飾的成員,其可訪問性是什么,結構體中沒有用public/protected/private修飾的成員,其可訪問性是什么?
public修飾的成員可以在任何地方被訪問
private修飾的成員只能由該類中的函數、其友元函數訪問;不能被任何其他訪問,該類對象也不能訪問。
protected修飾的成員可以被該類中函數、子類函數、友元函數訪問;但不能被該類對象訪問。
public可以被訪問,沒有修飾,類的默認為private,struct默認為public。
十、什么是封裝?其作用是什么?(google)
封裝就是將抽象得到的數據和行為(或功能)相結合,形成一個有機的整體,也就是將數據與操作數據的函數代碼進行有機結合,形成類。
作用:
使一部分成員充當類與外部的接口,而將其他成員隱藏起來,這樣就達到了對成員訪問權限的合理控制,使不同類之間的相互影響減少到最低限度,進而保護數據增強數據的安全性和簡化程序編寫工作。
十一、什么是構造函數?構造函數有返回值嗎?構造函數如何命名?構造函數可以重載嗎?什么是缺省構造函數(default constructor)?什么情況下,類中會有缺省構造函數?
構造函數主要用來在創建對象時初始化對象, 即為對象成員變量賦初始值。
構造函數沒有返回值。
構造函數是一個與其所在的類同名的函數。
構造函數可以重載。但是, 每個構造函數必須有不同的函數簽名。
如果構造函數沒有參數,或者構造函數的所有參數都有默認值,就可以稱其為缺省構造函數。一個類中,只能有一個缺省構造函數。
當沒有定義構造函數或者定義的構造函數沒有參數時,類中會有缺省構造函數。
十二、若父類中沒有缺省構造函數,則對派生類的構造函數有什么要求?
如果父類是一個無缺省參數的構造函數,那么對於派生類一旦沒有構造函數,那么就不會自動的先構造父類的構造函數,這是不允許的。
派生類中一定要有構造函數。
BaseballTeam(const string s[], int si) : Team(si)
派生類的構造函數通過初始化列表,對基類進行初始化。
十三、構造函數的作用是什么?什么時候會被調用?構造函數的執行順序是什么(父類與子類的構造函數、類自身與其數據成員的構造函數)?
構造函數主要用來在創建對象時初始化對象, 即為對象成員變量賦初始值。
當類被創建時,自動調用。
執行構造函數的順序:
父類的構造函數
數據成員的初始化(成員中有類,執行該類的構造函數)
子類的構造函數
十四、什么是類作用域(Class scope)、文件作用域(file scope)、函數作用域(function scope)?
類作用域:
類是有名成員的集合,類X的成員m具有類作用域,對成員m的訪問方式有如下三種:
1)如果X的成員函數中沒有聲明同名的局部作用域標識符,那么可以直接使用成員m
2)通過表達式x.m或X::m(訪問靜態成員)
3)通過ptr->m,其中ptr為指向X類的一個對象的指針
文件作用域:
在函數外部聲明的變量只在當前文件范圍內(包括文件內所有定義的函數)可用
在其他文件不可用。要使變量具有文件作用域,必須在變量的聲明前加static關鍵字。
當多個源文件鏈接成一個程序時,static可以避免一個文件中的全局變量與其它文件中的變量同名而發生沖突。
函數作用域:
(1)指在函數定義或者復合語句中,從標識符的定義點開始到函數或者一對花括號之間的程序段。
(2)在同一個局部作用域內不能出現相同名字的兩個局部變量(包括形參)。
(3)一個函數內的復合語句又是一個局部作用域,也就是在函數內有某個變量時,復合語句中可以有另外一個同名字的變量。
十五、為什么拷貝構造函數(copy constructor)的參數必須是按引用傳遞(by reference)而不能是按值傳遞(by value)?
1.無限遞歸調用:
當一個對象需要以值方式傳遞時編譯器會生成代碼調用它的拷貝構造函數以生成一個復本。如果類A的拷貝構造函數是以值方式傳遞一個類A對象作為參數的話,當需要調用類A的拷貝構造函數時,需要以值方式傳進一個A的對象作為實參;而以值方式傳遞需要調用類A的拷貝構造函數;結果就是調用類A的拷貝構造函數導致又一次調用類A的拷貝構造函數,這就是一個無限遞歸。
2在某些狀況下,類內成員變量需要動態開辟堆內存,如果實行位拷貝,也就是把對象里的值完全復制給另一個對象,如A=B。這時,如果B中有一個成員變量指針已經申請了內存,那A中的那個成員變量也指向同一塊內存。這就出現了問題:當B把內存釋放了(如:析構),這時A內的指針就是野指針了,出現運行錯誤。
十六、拷貝構造函數(復制構造函數)的作用是什么?什么是淺拷貝?什么是深拷貝?(google)
復制構造函數由編譯器調用來完成一些基於同一類的其他對象的構件及初始化。
淺拷貝只是對指針的拷貝,拷貝后兩個指針指向同一個內存空間,深拷貝不但對指針進行拷貝,而且對指針指向的內容進行拷貝,經深拷貝后的指針是指向兩個不同地址的指針。
十七、全局對象(Global scope objects)的構造函數、析構函數分別是什么時候被調用的?
自動局部對象(Automatic local objects)的構造函數、析構函數分別是什么時候被調用的?
靜態局部對象(static local objects)的構造函數、析構函數分別是什么時候被調用的?
a.全局變量構造函數程序運行前被調用,在main()函數返回后才被中對象才被銷毀,析構函數在程序結束前最后被調用。
b.自動局部變量,當程序執行到對象定義時,調用自動局部對象的構造函數。該對象的析構函數在對象離開范圍時調用(即離開定義對象的塊時)。自動對象的構造函數與析構函數在每次對象進人和離開范圍時調用。
c.靜態局部對象的構造函數只在程序執行首次到達對象定義時調用一次,對應的析構函數在main終止或調用exit函數時調用。
十八、父類成員中的public、protected、private成員,哪些在子類中是可以訪問的?
在公有繼承、私有繼承、受保護繼承三種繼承方式下,父類成員中的public、protected、private成員被繼承到子類后,其可訪問性分別是什么?
派生類是否可以繼承父類的構造函數和析構函數?
public 和protected是可以訪問的,private不可訪問。
公有繼承:public、protected、private
私有繼承:private、private、private
保護繼承:protected、protected、private
派生類不能繼承父類的構造函數和析構函數。
十九、多重繼承會帶來什么問題?在C++中是如何解決的?
問題1:類DC的對象中存在多個同名成員 x, 應如何使用?
問題2:類DC的對象中,存在兩份來自類BC0的成員K,如何區分?
解決方案:
在BC1類和BC2類繼承BC0時,其前面加上virtual關鍵字就可以實現虛擬繼承,使用虛擬繼承后,當系統碰到多重繼承的時候就會先自動加一個BC0的拷貝,當再次請求一個BC0的拷貝時就會被忽略,以保證繼承類成員函數的唯一性。
二十、要讓一個函數調用表現出多態特征,必須滿足哪些條件?
a.必須存在繼承關系;
b.子類重寫父類的方法。繼承關系中必須有同名的虛函數,並且它們是覆蓋關系(重載不行)。
c.存在基類的指針,通過該指針調用虛函數。
如果你喜歡這篇文章的話,動動小指,加個關注哦~
如果你也想成為程序員,想要快速掌握編程,這里為你分享一個學習企鵝圈子!
里面有資深專業軟件開發工程師,在線解答你的所有疑惑~C++入門“so easy”
編程學習書籍:
編程學習視頻:
