如果同時定義了兩個函數,一個帶const,一個不帶,會有問題嗎?
- 不會,這相當于函數的重載
#include<iostream>
class A{
public:void print()const{std::cout << "Hello" << std::endl;}void print(){std::cout << "World" << std::endl;}
};
int main(){A a{};const A const_a;a.print();const_a.print();return 0;
}
請你來說一說隱式類型轉換
- 首先,對于內置類型,低精度的變量給高精度變量賦值會發生隱式類型轉換,? ?int? ->? double
- 其次,對于只存在單個參數的構造函數的對象構造來說,函數調用可以直接使用該參數傳入,編譯器會自動調用其構造函數生成臨時對象
注意事項
- “可以用單個形參進行調用” 并不是指構造函數只能有一個形參,而是它可以有多個形參,但那些形參都是有默認實參的。 那么,什么是“隱式轉換”呢? 上面這句話也說了,是從 構造函數形參類型 到 該類類型 的一個編譯器的自動轉換。
- 代碼中可以看到,isSameISBN函數是期待一個BOOK類類型形參的,但我們卻傳遞了一個string類型的給它,這不是它想要的啊!還好,BOOK類中有個構造函數,它使用一個string類型實參進行調用,編譯器調用了這個構造函數,隱式地將stirng類型轉換為BOOK類型(構造了一個BOOK臨時對象),再傳遞給isSameISBN函數。 隱式類類型轉換還是會帶來風險的,正如上面標記,隱式轉換得到類的臨時變量,完成操作后就消失了,我們構造了一個完成測試后被丟棄的對象。 我們可以通過explicit聲明來抑制這種轉換:
- explicit BOOK(string ISBN,float price=0.0f):_bookISBN(ISBN),_price(price){}
- explicit關鍵字只能用于類內部的構造函數聲明上.這樣一來,BOOK類構造函數就不能用于隱式地創造對象了
- 可以使用一個實參進行調用,不是指構造函數只能有一個形參。 隱式類類型轉換容易引起錯誤,除非你有明確理由使用隱式類類型轉換,否則,將可以用一個實參進行調用的構造函數都聲明為explicit。 ? ?
- ?explicit只能用于類內部構造函數的聲明。它雖然能避免隱式類型轉換帶來的問題,但需要用戶能夠顯式創建臨時對象(對用戶提出了要求)。
#include <string>
#include <iostream>
using namespace std ;
class BOOK //定義了一個書類
{
private:string _bookISBN ; //書的ISBN號float _price ; //書的價格public://定義了一個成員函數,這個函數即是那個“期待一個實參為類類型的函數”//這個函數用于比較兩本書的ISBN號是否相同bool isSameISBN(const BOOK & other ){return other._bookISBN==_bookISBN;}//類的構造函數,即那個“能夠用一個參數進行調用的構造函數”(雖然它有兩個形參,但其中一個有默認實參,只用一個參數也能進行調用)BOOK(string ISBN,float price=0.0f):_bookISBN(ISBN),_price(price){}
};int main()
{BOOK A("A-A-A");BOOK B("B-B-B");cout<<A.isSameISBN(B)<<endl; //正經地進行比較,無需發生轉換cout<<A.isSameISBN(string("A-A-A"))<<endl; //此處即發生一個隱式轉換:string類型-->BOOK類型,借助BOOK的構造函數進行轉換,以滿足isSameISBN函數的參數期待。cout<<A.isSameISBN(BOOK("A-A-A"))<<endl; //顯式創建臨時對象,也即是編譯器干的事情。}
說說你了解的類型轉換
- reinterpret_cast:可以用于任意類型的指針之間的轉換,對轉換的結果不做任何保證
- dynamic_cast:這種其實也是不被推薦使用的,更多使用static_cast,dynamic本身只能用于存在虛函數的父子關系的強制類型轉換,對于指針,轉換失敗則返回nullptr,對于引用,轉換失敗會拋出異常。(1)dynamic_cast是運行時處理的,運行時要進行類型檢查,而其他三種都是編譯時完成的;(2)不能用于內置基本數據類型間的強制轉換;(3)使用dynamic_cast進行轉換時,基類中一定要有虛函數,否則編譯不通過;(4)dynamic_cast轉換若成功,返回的是指向類的指針或引用;若失敗則會返回NULL;(5)在類的轉換時,在類層次間進行上行轉換時,dynamic_cast和static_cast的效果是一樣的。在進行下行轉換時,dynamic_cast具有類型檢查的功能,比static_cast更安全。向下轉換的成敗取決于將要轉換的類型,即要強制轉換的指針所指向的對象實際類型與將要轉換后的類型一定要相同,否則轉換失敗。? 下行轉換,使用基類class? 創建 其派生類對象的時候,新建的對象只可以使用 基類的相關public、protected內容 和 本派生類所創建的獨有的方法
- 參考此例子??
#include <iostream>class Shape{
public:Shape();virtual ~Shape();virtual double calcArea();protected:double i_mNumber;
};class Circle : public Shape{
public:Circle(double r);~Circle();
protected:double m_iR;
};
int main(){double x = 2.5;//static_castint y = (int)x;//C語言int z = static_cast<int>(x);//C++//dynamic_castShape *p = new Circle(2.0);Circle *q = dynamic_cast<Circle *>(p);//reinterpret_castint r = 1000;int *w = reinterpret_cast<int *>(r);//將數值轉化為地址 很危險//const int c = 0;
// int *o = &x;//Errorint *g = const_cast<int *>(&c);
}
參考鏈接
- C++中四種cast(強制)轉換?
- const_cast:對于未定義const版本的成員函數,我們通常需要使用const_cast來去除const引用對象的const,完成函數調用。另外一種使用方式,結合static_cast,可以在非const版本的成員函數內添加const,調用完const版本的成員函數后,再使用const_cast去除const限定。
- static_cast:完成基礎數據類型;同一個繼承體系中類型的轉換;任意類型與空指針類型void* 之間的轉換。
參考鏈接
- 你必須知道的指針基礎-8.棧空間與堆空間?
- 棧空間和堆空間大小
?請你來說一說C++函數棧空間的最大值
- 默認是1M,不過可以調整?
- 補充:window和Linux不一樣,linux如圖stack size所示 為8kb,win為2kb;而堆本質是使用鏈表的形式申請內存空間,和操作系統的虛擬內存掛鉤,一般大小為2G
請你來說一說extern“C”
- C++調用C函數需要extern C,因為C語言沒有函數重載
參考鏈接
- extern “C”的作用詳解
- extern "C":實現C++和C的混合編程
請你回答一下new/delete與malloc/free的區別是什么
- 首先,new/delete是C++的關鍵字,而malloc/free是C語言的庫函數,后者使用必須指明申請內存空間的大小,對于類類型的對象,后者不會調用構造函數和析構函數
補充
- 1、new分配內存按照數據類型進行分配,malloc分配內存按照指定的大小分配;
- 2、new返回的是指定對象的指針,而malloc返回的是void*,因此malloc的返回值一般都需要進行類型轉化。
- 3、new不僅分配一段內存,而且會調用構造函數,malloc不會。
- 4、new分配的內存要用delete銷毀,malloc要用free來銷毀;delete銷毀的時候會調用對象的析構函數,而free則不會。
- 5、new是一個操作符可以重載,malloc是一個庫函數。
- 6、malloc分配的內存不夠的時候,可以用realloc擴容。new沒用這樣操作。
- 7、new如果分配失敗了會拋出bad_malloc的異常,而malloc失敗了會返回NULL。
- 8、申請數組時:new[]一次分配所有內存,多次調用構造函數,搭配使用delete[]。delete[]多次調用析構函數,銷毀數組中的每個對象。而malloc則只能sizeof(int) * n。
參考鏈接
- 請你來回答一下new和malloc的區別
請你說說你了解的RTTI
- 運行時類型檢查,在C++層面主要體現在dynamic_cast和typeid,VS中虛函數表的-1位置存放了指向type_info的指針。對于存在虛函數的類型,typeid和dynamic_cast都會去查詢type_info
參考鏈接
- RTTI
- C++中的RTTI機制
- Chapter12:多態——從虛函數表到RTTI(二)
請你說說虛函數表具體是怎樣實現運行時多態的?
- 子類若重寫父類虛函數,虛函數表中,該函數的地址會被替換,對于存在虛函數的類的對象,在VS中,對象的對象模型的頭部存放指向虛函數表的指針,通過該機制實現多態。
請你說說C語言是怎么進行函數調用的?
- 每一個函數調用都會分配函數棧,在棧內進行函數執行過程。調用前,先把返回地址壓棧,然后把當前函數的esp指針壓棧。
請你說說C語言參數壓棧順序?
- 從右到左
請你說說C++如何處理返回值?
生成一個臨時變量,把它的引用作為函數參數傳入函數內。
請你回答一下C++中拷貝賦值函數的形參能否進行值傳遞?
- 不能。如果是這種情況下,調用拷貝構造函數的時候,首先要將實參傳遞給形參,這個傳遞的時候又要調用拷貝構造函數。如此循環,無法完成拷貝,棧也會滿。
請你回答一下malloc與new區別
- malloc需要給定申請內存的大小,返回的void* 指針需要強轉
- new會調用構造函數,不用指定內存大小,返回的指針不用強轉
請你說一說select
- select在使用前,先將需要監控的描述符對應的bit位置1,然后將其傳給select,當有任何一個事件發生時,select將會返回所有的描述符,需要在應用程序自己遍歷去檢查哪個描述符上有事件發生,效率很低,并且其不斷在內核態和用戶態進行描述符的拷貝,開銷很大
?請你說說fork,wait,exec函數
- 父進程產生子進程使用fork拷貝出來一個父進程的副本,此時只拷貝了父進程的頁表,兩個進程都讀同一塊內存,當有進程寫的時候使用寫實拷貝機制分配內存
- exec函數可以加載一個elf文件去替換父進程,從此父進程和子進程就可以運行不同的程序了。fork從父進程返回子進程的pid,從子進程返回0.調用了wait的父進程將會發生阻塞,直到有子進程狀態改變,執行成功返回0,錯誤返回-1。
- exec執行成功則子進程從新的程序開始運行,無返回值,執行失敗返回-1
請你回答一下靜態函數和虛函數的區別
- 靜態函數在編譯的時候就已經確定運行時機,虛函數在運行的時候動態綁定。虛函數因為用了虛函數表機制,調用的時候會增加一次內存開銷,動態切換
請你說一說重載和覆蓋
- 重載:兩個函數名相同,但是參數列表不同(個數,類型),返回值類型沒有要求,在同一作用域中
- 重寫:子類繼承了父類,父類中的函數是虛函數,在子類中重新定義了這個虛函數,這種情況是重寫
請你說一說static關鍵字
- 1.加了static關鍵字的全局變量只能在本文件中使用。例如在a.c中定義了static int a=10;那么在b.c中用extern int a是拿不到a的值,a的作用域只在a.c中。
- 2.static定義的靜態局部變量分配在數據段上,普通的局部變量分配在棧上,會因為函數棧幀的釋放而被釋放掉。
- 3. 對一個類中成員變量和成員函數來說,加了static關鍵字,則此變量/函數就沒有了this指針了,必須通過類名才能訪問
請你說一說strcpy和strlen
- strcpy是字符串拷貝函數,原型:? char *strcpy(char* dest, const char *src);
- 從src逐字節拷貝到dest,直到遇到'\0'結束,因為沒有指定長度,可能會導致拷貝越界,造成緩沖區溢出漏洞,安全版本是strncpy函數。
- strlen函數是計算字符串長度的函數,返回從開始到'\0'之間的字符個數。