C++面試寶典 基本語言(三)

如果同時定義了兩個函數,一個帶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_casttypeid,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'之間的字符個數。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/446562.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/446562.shtml
英文地址,請注明出處:http://en.pswp.cn/news/446562.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C++ primer 第9章 順序容器

文章目錄順序容器類型確定使用哪種順序容器容器庫概覽容器操作迭代器迭代器支持的所有操作迭代器支持的所有運算迭代器范圍對構成范圍的迭代器的要求標準庫迭代器范圍左閉右開的三種性質容器定義和初始化將一個新容器創建為另一個容器的拷貝將array拷貝到vector中的代碼與順序容…

常用單位換算

字節單位換算 B(byte)字節 bit 位 1B 8 bit 1KB&#xff08;Kilobyte&#xff0c;千字節&#xff09;1024B 2^10 B&#xff1b; 1MB&#xff08;Megabyte&#xff0c;兆字節&#xff0c;百萬字節&#xff0c;簡稱“兆”&#xff09;1024KB 2^20 B&#xff1b; 1GB&#xf…

牛客網C++面經 容器和算法

原文網址 參考網址 C語言中文網 請你來說一下map和set有什么區別&#xff0c;分別又是怎么實現的&#xff1f; map和set都是C的關聯容器&#xff0c;其底層實現都是紅黑樹&#xff08;RB-Tree&#xff09;。由于 map 和set所開放的各種操作接口&#xff0c;RB-tree 也都提供…

C語言指針-字符指針整型指針char*s int*a

案例代碼 #include<stdio.h> #include<stdlib.h> #include<string.h> int main() {//字符指針char *pstr"good dog ww";printf("字符指針指向的字符串內容:%s\n",pstr);printf("字符指針本身的地址:%p\n",&pstr);printf…

C++ primer 第10章 泛型算法

文章目錄概述findcount初識泛型算法只讀算法只讀算法accumulate只讀算法equal寫容器元素的算法算法fill算法fill_nback_inserter算法copy算法replace replace_copy重排容器元素的算法sortuniqueunique_copy定制操作向算法傳遞函數謂詞算法stable_sort算法partitionlambda表達式…

C語言常用字符串函數

概括 代碼 #include<stdlib.h> #include<stdio.h> #include<string.h> int main() {//常用字符串函數char a[]"abcSDFbnm";char b[]"SD";printf("a的字符串長度:%d\n",strlen(a));printf("b的字符串長度:%d\n",str…

C++ primer 第11章 關聯容器

文章目錄使用關聯容器map示例關聯容器概述定義關聯容器關聯容器值初始化multimap和multiset關鍵字類型的要求pair類型pair上的操作關聯容器操作關聯容器額外的類型別名關聯容器迭代器map迭代器set迭代器關聯容器和算法添加元素向map添加元素檢測insert的返回值使用insert代替下…

C++ primer 第12章 動態內存

文章目錄前言動態內存與智能指針shared_ptr類shared_ptr和unique_ptr都支持的操作shared_ptr獨有的操作make_shared 函數shared_ptr的拷貝和賦值shared_ptr自動銷毀所管理的對象shared_ptr還會自動釋放相關聯的內存程序使用動態內存出于以下原因直接管理內存使用new動態分配和初…

C語言順序查找二分查找

介紹 順序查找 按照順序一個個查找 #include<stdio.h> //順序查找 int search(int arr[],int len,int aim) {int i;for(i0;i<len;i){if(arr[i]aim){return i;//返回下標 }}return -1;//表示未查詢到} int main() {int arr[]{13,355,256,65,234,-1,35,-6,-3,-4,0};…

C++ primer 第12章 12.3 使用標準庫:文本查詢程序

文章目錄使用標準庫&#xff1a;文本查詢程序文本查詢程序設計數據結構在類之間共享數據自己的文本查詢程序書中的文本查詢程序使用標準庫&#xff1a;文本查詢程序 我們將實現一個簡單的文本查詢程序&#xff0c;作為標準庫相關內容學習的總結。 我們的程序允許用戶在一個給…

C語言二維數組 int arr[2][3]

基礎使用 先遍歷行再遍歷列 #include<stdio.h> //二維數組的基本使用 int main() {//二維數組的初始化int arr1[2][2]{{2,2},{0,0}};int arr2[2][3]{2,2,2,8,8,8};int arr3[6][9];int i,j;for(i0;i<6;i){for(j0;j<9;j){arr3[i][j]1;}}arr3[2][5]0;//打印printf(&…

牛客網C++面經 類和數據抽象

請你來說一下C中struct和class的區別 在C中&#xff0c;可以用struct和class定義類&#xff0c;都可以繼承。區別在于&#xff1a;structural的默認繼承權限和默認訪問權限是public&#xff0c;而class的默認繼承權限和默認訪問權限是private。另外&#xff0c;class還可以定義…

C++ primer 第13章 拷貝控制

文章目錄前言拷貝、賦值與銷毀拷貝構造函數合成拷貝構造函數拷貝初始化和直接初始化拷貝初始化的發生&#xff1a;參數和返回值拷貝初始化的限制拷貝賦值運算符重載賦值運算符合成拷貝賦值運算符析構函數析構函數完成的工作什么時候會調用析構函數合成析構函數代碼片段調用幾次…

C語言 指針自增自減加減運算 p++ p+i

介紹 自增自減代碼 #include<stdio.h> #include<string.h> //指針自增--short void increase(short *arr,int len) {int i;arr&arr[0];for(i0;i<len;i){printf("arr[%d]%d,address%p\n",i,*arr,arr);arr;} }//指針自減--char void decrease(char…

C++ 編譯與底層

原文鏈接 編譯與底層請你來說一下一個C源文件從文本到可執行文件經歷的過程&#xff1f; 對于C源文件&#xff0c;從文本到可執行文件一般需要四個過程&#xff1a;預處理階段&#xff1a;對源代碼文件中文件包含關系&#xff08;頭文件&#xff09;、預編譯語句&#xff08;…

C語言 指針數組-字符指針數組整型指針數組 char*s[3] int*a[5] 數組指針int(*p)[4]

基本介紹 1.指針數組:由n個指向整型元素的指針而組成,里面存放指針 Int *ptr[3]; 2.地址: ptr[i]:元素地址 &ptr[i]:指針地址 圖示 代碼: 內存布局: 代碼 #include<stdio.h> #include<string.h> //指針數組--int void pointer(int *arr,int len) {int …

uninitialized_copy測試代碼示例

原測試代碼如下&#xff1a; int main() {vector<int>v1{1,3,5,7,9,2,4,6,8};allocator<int>alloc;auto data alloc.allocate(9);uninitialized_copy(v1.begin(),v1.end(), data);auto end data 9;while(data!end) {cout << *data <<" "…

C語言的地址 內存

取地址在CPU的寄存器產生&#xff0c;不占據內存地址由計算器總線&#xff0c;地址作為常量不消耗內存指針 存儲不同的地址&#xff0c;間接賦值空類型指針 void* 類型指針 不可以取數據 或者修改數據 需要進行強制類型轉換int num 10;void *p &num;std::cout << …

C語言 多重指針--整型字符字符串 int**pp

介紹 多重指針:一個指針指向另一個指針 離值越近的指針級別越大:一級 內存布局 代碼 圖示: 多重指針–整型 #include<stdio.h> #include<string.h> //多重指針--整型//二級指針 void two() {printf("二級指針:\n");int a896;int *p&a,**pp&…

C++ primer 第13章 拷貝控制

文章目錄前言拷貝、賦值與銷毀拷貝構造函數合成拷貝構造函數拷貝初始化和直接初始化拷貝初始化的發生&#xff1a;參數和返回值拷貝初始化的限制拷貝賦值運算符重載賦值運算符合成拷貝賦值運算符析構函數析構函數完成的工作什么時候會調用析構函數合成析構函數代碼片段調用幾次…