面試總結(C++基礎)
C++面試知識點彙總:
一、多型性:實現了“一個介面,多種方法”。程式在執行時才決定呼叫的函式。
從實現的角度來講,多型可以分為兩類:編譯時的多型性和執行時的多型性。前者是通過靜態聯編來實現的,比如C++中通過函式的過載和運算子的過載。後者則是通過動態聯編來實現的,在C++中執行時的多型性主要是通過虛擬函式來實現的。
1)虛擬函式:(1)因為虛擬函式使用的基礎是賦值相容,而賦值相容成立的條件是派生類從基類公有派生而來。所以使用虛擬函式,派生類必須是基類公有派生的;(2)定義虛擬函式,不一定要在最高層的類中,而是看在需要動態多型性的幾個層次中的最高層類中宣告虛擬函式;(3)雖然在上述示例程式碼中
純虛擬函式:類內的虛擬函式宣告語句的分號前加“=0”即可,必須在類的外部定義函式體。
至少含有一個純虛擬函式的類,為抽象類。
抽象類只能作為其他類的基類來使用,不能建立抽象類物件;(2)不允許從具體類中派生出抽象類(不包含純虛擬函式的普通類);(3)抽象類不能用作函式的引數型別、返回型別和顯示轉化型別;(4)如果派生類中沒有定義純虛擬函式的實現,而只是繼承成了基類的純虛擬函式。那麼該派生類仍然為抽象類。一旦給出了對基類中虛擬函式的實現,那麼派生類就不是抽象類了,而是可以建立物件的具體類;
2)運算子過載:在實際的運算子過載函式聲明當中,要不定義其為要操作類的成員函式或類的友元函式。
3)函式過載:是指在同一作用域內,可以有一組具有相同函式名,不同引數列表的函式,這組函式被稱為過載函式。過載函式通常用來命名一組功能相似的函式,這樣做減少了函式名的數量,避免了名字空間的汙染,對於程式的可讀性有很大的好處。
多型有兩個好處:
1. 應用程式不必為每一個派生類編寫功能呼叫,只需要對抽象基類進行處理即可。大大提高程式的可複用性。//繼承
2. 派生類的功能可以被基類的方法或引用變數所呼叫,這叫向後相容,可以提高可擴充性和可維護性。 //多型的真正作用
二、動態繫結怎麼實現?
C++的函式呼叫預設不使用動態繫結。要觸發動態繫結,必須滿足兩個條件:
1)只有指定為虛擬函式的成員函式才能進行動態繫結
2)必須通過引用或指標進行函式呼叫
因為每個派生類物件中都擁有基類部分,所以可以使用基類型別的指標或引用來引用派生類物件。
三、指標和引用的區別:
1)首先,引用不可以為空,但指標可以為空。前面也說過了引用是物件的別名,引用為空——物件都不存在,怎麼可能有別名!故定義一個引用的時候,必須初始化。而宣告指標是可以不指向任何物件,也正是因為這個原因,使用指標之前必須做判空操作,而引用就不必。
2)其次,引用不可以改變指向,對一個物件"至死不渝";但是指標可以改變指向,而指向其它物件。說明:雖然引用不可以改變指向,但是可以改變初始化物件的內容。例如就++操作而言,對引用的操作直接反應到所指向的物件,而不是改變指向;而對指標的操作,會使指標指向下一個物件,而不是改變所指物件的內容。
3)再次,引用的大小是所指向的變數的大小,因為引用只是一個別名而已;指標是指標本身的大小,4個位元組。
4)最後,引用比指標更安全。由於不存在空引用,並且引用一旦被初始化為指向一個物件,它就不能被改變為另一個物件的引用,因此引用很安全。對於指標來說,它可以隨時指向別的物件,並且可以不被初始化,或為NULL,所以不安全。const 指標雖然不能改變指向,但仍然存在空指標,並且有可能產生野指標(即多個指標指向一塊記憶體,free掉一個指標之後,別的指標就成了野指標)。
5)作為引數傳遞時,兩者不同。指標傳遞引數的本質是值傳遞,被調函式對形參的任何操作作為區域性變數進行的,不會影響到主調函式的實參。如果想通過指標引數傳遞來改變主調函式中的相關變數,就得使用指標的指標,或者指標引用。引用傳遞引數的本質是傳遞實參的地址,被調函式對形參的任何操作都影響了主調函式的實參。
總而言之,言而總之——它們的這些差別都可以歸結為"指標指向一塊記憶體,它的內容是所指記憶體的地址;而引用則是某塊記憶體的別名,引用不改變指向。"
四、四種強制型別轉換:(網易兩次面試均出現)
C風格的型別轉換——強制型別轉換(type) expression.
C++中型別轉換四種分別為:static_cast ,const_cast,dynamic_cast,reinterpret_cast.
1)static_cast. 最常用的型別轉換符,在正常狀況下的型別轉換,如把int轉換為float,如:int i;float f; f=(float)i;或者f=static_cast<float>(i);
還可以用於將編譯器無法自動執行的型別轉換。
例如,void *p=&d; double *dp=static_cast(double *)(p) //將void型別指標轉換為double型別。
2)const_cast. 用於取出底層const屬性,把const型別的指標變為非const型別的指標.如:const int *fun(int x,int y){}int *ptr=const_cast<int *>(fun(2,3)).
3)dynamic_cast.用於將基類的指標或引用型別安全地轉換成派生類的指標或引用,在執行時檢查該轉換是否型別安全,但只在多型型別時合法,即該類至少具有一個虛擬函式。
例如:基類Base(至少有一個虛擬函式),派生類Derived,
Base *bp; Derived *dp=dynamic_cast<Base*>(bp)。
(1)其他三種都是編譯時完成的,dynamic_cast是執行時處理的,執行時要進行型別檢查。
(2)不能用於內建的基本資料型別的強制轉換。
(3)dynamic_cast轉換如果成功的話返回的是指向類的指標或引用,轉換失敗的話前者返回0,後者丟擲bad_cast異常。
(4)使用dynamic_cast進行轉換的,基類中一定要有虛擬函式,否則編譯不通過。
B中需要檢測有虛擬函式的原因:類中存在虛擬函式,就說明它有想要讓基類指標或引用指向派生類物件的情況,此時轉換才有意義。
這是由於執行時型別檢查需要執行時型別資訊,而這個資訊儲存在類的虛擬函式表(關於虛擬函式表的概念,詳細可見<Inside c++ object model>)中,
(5)只有定義了虛擬函式的類才有虛擬函式表。dynamic_cast與static_cast具有相同的基本語法,dynamic_cast主要用於類層次間的上行轉換和下行轉換,還可以用於類之間的交叉轉換。在類層次間進行上行轉換時,dynamic_cast和static_cast的效果是一樣的;在進行下行轉換時,dynamic_cast具有型別檢查的功能,比static_cast更安全。如:
class C
{
//…C沒有虛擬函式
};
class T{
//…
}
int main()
{
dynamic_cast<T*> (new C);//錯誤
}
此時如改為以下則是合法的:
class C
{
public:
virtual void m() {};// C現在是 多型
}
4)interpret_cast
interpret是解釋的意思,reinterpret即為重新解釋,此識別符號的意思即為資料的二進位制形式重新解釋,但是不改變其值。如:int i; char *ptr="hello freind!"; i=reinterpret_cast<int>(ptr);這個轉換方式很少使用。
五、操作符過載
operator是C++的關鍵字,它和運算子一起使用,表示一個運算子函式。
理解時應將operator=整體上視為一個函式名。
操作符過載的實現方式有兩種,即通過“友元函式”或者“類成員函式”。
利用友元函式過載二元操作符”-“時,形式引數是兩個,而利用類成員函式時,形式引數卻只有一個。這時因為類成員函式中存在this指標,這相當於一個引數,所以類成員實現操作符過載需要的形式引數比原來少一個,這比如:利用類成員函式實現一元操作符”-“,就不需要引數了。也正是因為這個原因,友元函式實現的操作符過載是有限制的,比如:[] ,(),->和 =不能利用友元函式實現運算子的過載。
運算子過載也是要遵循一些原則的:
1.C++中只能對已有的C++運算子進行過載,不允許使用者自己定義新的運算子。
2.C++中絕大部分的運算子可過載,除了成員訪問運算子.,作用域運算子::,長度運算子sizeof以及條件運算子?:。
3.運算子過載後不能改變運算子的操作物件(運算元)的個數。如:"+"是實現兩個運算元的運算子,過載後仍然為雙目運算子。
4.過載不能改變運算子原有的優先順序和原有的結合性。
6.運算子過載不能全部是C++中預定義的基本資料,這樣做的目的是為了防止使用者修改用於基本型別資料的運算子性質。
為了區分前後,增量運算子中,放上一個整數形參,就是後增量執行符,它是值返回,對於前增量沒有形參,而且是引用返回。即用++()表示前自增,用++(int)後自增。
六、記憶體對齊原則
顯示規定採用幾個位元組對齊
#pragma pack(n) c編譯器將按照n個位元組對齊。
•原則1、資料成員對齊規則:結構(struct或聯合union)的資料成員,第一個資料成員放在offset為0的地方,以後每個資料成員儲存的起始位置要從該成員大小的整數倍開始(比如int在32位機為4位元組,則要從4的整數倍地址開始儲存)。
•原則2、結構體作為成員:如果一個結構裡有某些結構體成員,則結構體成員要從其內部最大元素大小的整數倍地址開始儲存。(struct a裡存有struct b,b裡有char,int,double等元素,那b應該從8的整數倍開始儲存。)
•原則3、收尾工作:結構體的總大小,也就是sizeof的結果,必須是其內部最大成員的整數倍,不足的要補齊。
七、模板怎麼實現的?
模板是C++支援引數化多型的工具,使用模板可以使使用者為類或者函式宣告一種一般模式,使得類中的某些資料成員或者成員函式的引數、返回值取得任意型別。
模板是一種對型別進行引數化的工具;通常有兩種形式:函式模板和類模板;
函式模板針對僅引數型別不同的函式;
類模板針對資料成員和成員函式型別不同的類。
注意:模板的宣告或定義只能在全域性,名稱空間或類範圍內進行。即不能在區域性範圍,函式內進行,比如不能在main函式中宣告或定義一個模板。
1)函式模板通式
1、函式模板的格式:
template <class 形參名,class 形參名,......> 返回型別 函式名(引數列表)
{
函式體
}
其中template和class是關鍵字,class可以用typename 關鍵字代替,在這裡typename 和class沒區別,<>括號中的引數叫模板形參,模板形參和函式形參很相像,模板形參不能為空。一旦聲明瞭模板函式就可以用模板函式的形參名宣告類中的成員變數和成員函式,即可以在該函式中使用內建型別的地方都可以使用模板形參名。模板形參需要呼叫該模板函式時提供的模板實參來初始化模板形參,一旦編譯器確定了實際的模板實參型別就稱為例項化了函式模板的一個例項。比如swap的模板函式形式為
template <class T> void swap(T& a, T& b){},
2、注意:對於函式模板而言不存在 h(int,int) 這樣的呼叫,不能在函式呼叫的引數中指定模板形參的型別,對函式模板的呼叫應使用實參推演來進行,即只能進行 h(2,3) 這樣的呼叫,或者int a, b; h(a,b)。
2)類模板通式
1、類模板的格式為:
template<class 形參名,class 形參名,…> class 類名
{ ... };
類模板和函式模板都是以template開始後接模板形參列表組成,模板形參不能為空,一旦聲明瞭類模板就可以用類模板的形參名宣告類中的成員變數和成員函式,即可以在類中使用內建型別的地方都可以使用模板形參名來宣告。比如
template<class T> class A{public: T a; T b; T hy(T c, T &d);};
在類A中聲明瞭兩個型別為T的成員變數a和b,還聲明瞭一個返回型別為T帶兩個引數型別為T的函式hy。
2、類模板物件的建立:比如一個模板類A,則使用類模板建立物件的方法為A<int> m;在類A後面跟上一個<>尖括號並在裡面填上相應的型別,這樣的話類A中凡是用到模板形參的地方都會被int 所代替。當類模板有兩個模板形參時建立物件的方法為A<int, double> m;型別之間用逗號隔開。
3、對於類模板,模板形參的型別必須在類名後的尖括號中明確指定。比如A<2> m;用這種方法把模板形參設定為int是錯誤的(編譯錯誤:error C2079: 'a' uses undefined class 'A<int>'),類模板形參不存在實參推演的問題。也就是說不能把整型值2推演為int 型傳遞給模板形參。要把類模板形參調置為int 型必須這樣指定A<int> m。
4、在類模板外部定義成員函式的方法為:
template<模板形參列表> 函式返回型別 類名<模板形參名>::函式名(引數列表){函式體},
比如有兩個模板形參T1,T2的類A中含有一個void h()函式,則定義該函式的語法為:template<class T1,class T2> void A<T1,T2>::h(){}。
注意:當在類外面定義類的成員時template後面的模板形參應與要定義的類的模板形參一致。
5、再次提醒注意:模板的宣告或定義只能在全域性,名稱空間或類範圍內進行。即不能在區域性範圍,函式內進行,比如不能在main函式中宣告或定義一個模板。
有三種類型的模板形參:型別形參,非型別形參和模板形參。
八、指標和const的用法(四種情況說了一下)
const是一個C語言的關鍵字,它限定一個變數不允許被改變。使用const在一定程度上可以提高程式的安全性和可靠性
指向常量的指標:
const int *pa;
int const *pa;
兩者等價。因為指向常量的指標有時候會指向常量,所以它具有這個性質:“不能靠解引用改變它指向的物件的值”,以此保護它所指向的常量的常量性:
*pa =d; // 不可行(d是已經宣告過的整型)
但指標本身的值是可變的:
pa=& d; // 可行(d是已經宣告過的整型)
而且指向常量的指標有時候也會指向變數,如下:
int t,u;
const int *pa;
pa =&t; //可行,指向變數t
pa =&u; //也可行,指向變數u
我們可以把它理解成:“為了指向常量而發明的指標”,這樣比較貼切。
常量指標:
int *const pa =&n; // n是之前已經宣告過的整型變數,注意必須是變數,理由見下
“常量指標”即指標本身的值是常量,但“能靠解引用改變它指向的物件的值”,如下:
pa=&d; // 不可行(d是已經宣告過的整型)
*pa =d; // 可行(d是已經宣告過的整型)
因為常量指標也是一種const常量,所以它同樣必須在第一次宣告時就初始化,不過它的初始值縮小為只能是變數(的地址),因為只有變數才能確保以後能靠解引用而改變它指向的物件的值。這使得常量指標不象一般的const常量,用變數或常量初始化都可以。
也就是說,常量指標反而總是指向變數的。
九、虛擬函式、純虛擬函式、虛擬函式與解構函式?(純虛擬函式如何定義,為什麼解構函式要定義成虛擬函式)
見程式設計師面試寶典4,P117。
十、行內函數(講了一下行內函數的優點以及和巨集定義的區別)
1)什麼是行內函數?
答:定義在類宣告之中的成員函式,在函式返回型別前加上inline關鍵字,將自動地成為行內函數。將函式定義為行內函數,一般就是將在程式中每個呼叫點上“內聯地”展開。
2)行內函數適用情況:
1.一個函式被重複呼叫;
2.函式只有幾行,且不包含for,while,switch語句。
行內函數應該放在標頭檔案中定義,這一點不同於其他函式。
行內函數可能在程式中定義不止一次,只要行內函數的定義在某個原始檔中只出現一次,而且在所有的原始檔中,其定義必須是相同的。如果inline函式的定義和宣告是分開的,而在另外一個檔案中需要呼叫這些inline函式得時候,內聯是無法在這些呼叫函式內展開的。這樣行內函數在全域性範圍內就失去了作用。解決的辦法就是把行內函數得定義放在標頭檔案中,當其它檔案要呼叫這些行內函數的時候,只要包含這個標頭檔案就可以了。把行內函數的定義放在標頭檔案中,可以確保在呼叫函式時所使用的定義是相同的,並保證在呼叫點該函式的定義對呼叫點可見。
行內函數具有一般函式的特性,它與一般函式所不同之處只在於函式呼叫的處理:
一般函式進行呼叫時,要將程式執行權轉到被呼叫函式中,然後再返回到呼叫它的函式中;而行內函數在呼叫時,是將呼叫表示式用行內函數體來替換。
內聯機制被引入C++作為對巨集(Macro)機制的改進和補充(不是取代)。行內函數的引數傳遞機制與普通函式相同。但是編譯器會在每處呼叫行內函數的地方將行內函數的內容展開。這樣既避免了函式呼叫的開銷又沒有巨集機制的前三個缺陷。
但是程式程式碼中的關鍵字"inline"只是對編譯器的建議:被"inline"修飾的函式不一定被內聯(但是無"inline"修飾的函式一定不是)。
內聯使用不恰當是會有副作用的:會帶來程式碼膨脹,還有可能引入難以發現的程式臭蟲。
a.從inline的原理,我們可以看出,inline的原理,是用空間換取時間的做法,是以程式碼膨脹(複製)為代價,僅僅省去了函式呼叫的開銷,從而提高函式的執行效率。如果執行函式體內程式碼的時間,相比於函式呼叫的開銷較大,那麼效率的收穫會很少。所以,如果函式體程式碼過長或者函式體重有迴圈語句,if語句或switch語句或遞迴時,不宜用內聯。
b.關鍵字inline 必須與函式定義體放在一起才能使函式成為內聯,僅將inline 放在函式宣告前面不起任何作用。行內函數呼叫前必須宣告。
行內函數:
(1)行內函數定義和作用:
將一個函式宣告為inline,那麼函式就成為行內函數。行內函數通常就是它在程式中每個呼叫點上“內聯地”展開。從定義上看,行內函數跟一般函式不一樣,一般函式呼叫的時候是需要呼叫開銷的(比如出棧入棧等操作),行內函數從定義上看更像是巨集,但是跟巨集不一樣。
行內函數的作用主要就是使用在一些短小而使用非常頻繁的函式中,為了減少函式呼叫的開銷,為了避免使用巨集(在c++中,巨集是不建議使用的)。比如行內函數inline int func(int x){return x*x;} 在呼叫的時候cout<<func(x)<<endl,在編譯時將被展開為:
cout<<(x*x)<<endl;
(3)如何使用行內函數和禁止內聯:
要讓一個函式稱為行內函數,有兩種方法:一種是把函式加上inline關鍵字;一種是在類的說明部分定義的函式,預設就是內聯的。
要禁止編譯器進行內聯,可以使用#pragma auto_inline編譯指令或者改變編譯引數。
行內函數注意事項:
(1)行內函數一定會內聯展開嗎?答案是否定的。對於行內函數,程式只是提供了一個“內聯建議”,即建議編譯器把函式用內聯展開,但是真正是否內聯,是由編譯器決定的,對於函式體過大的函式,編譯器一般不會內聯,即使制定為行內函數。
(2)在行內函數內部,不允許用迴圈語句和開關語句(if或switch)。行內函數內部有迴圈和開關,也不會出錯,但是編譯器會把它當做非行內函數的。
(3)關鍵字inline必須與函式定義體放在一起才能使函式真正內聯,僅把inline放在函式宣告的前面不起任何作用。因為inline是一種用於實現的關鍵字,不是一種用於宣告的關鍵字。行內函數的宣告是不需要加inline關鍵字的,行內函數的定義是必須加inline的(除了類的定義部分的預設行內函數),儘管很多書宣告定義都加了,要注意理解宣告和定義的區別。
(4) 在一個檔案中定義的行內函數不能在另一個檔案中使用。它們通常放在標頭檔案中共享。
(5) 行內函數的定義必須在第一次呼叫之前。注意,這裡是定義之前,不僅僅是宣告之前。對於普通函式,可以在呼叫之前宣告,呼叫程式碼之後具體定義(實現函式),但是行內函數要實現內聯,必須先定義再呼叫,否則編譯器會把在定義之前呼叫的行內函數當做普通函式進行呼叫。
(6) 說明:上面這些inline的注意事項,在程式設計時要自己注意,因為上面的注意事項不遵守很多並不會引起編譯錯誤,只是會導致寫了inline的函式不是行內函數,從而與預期的目的不一樣。所以很多沒法用程式例項說明到底編譯器是按照inline還是非inline呼叫的,或許分析彙編程式碼能看出,但是水平有限,就不多分析了。
使用行內函數至少有如下兩個優點。
(1)減少因為函式呼叫引起開銷,主要是引數壓棧、棧幀開闢與回收,以及暫存器儲存與恢復等。從而提高函式的執行效率。
(2)內聯後,編譯器在處理呼叫行內函數的函式(如上例中的foo()函式)時,因為可供分析的程式碼更多,因此它能做的優化更深入徹底。前一條優點對於開發人員來說往往更顯而易見一些,但往往這條優點對最終程式碼的優化可能貢獻更大。
行內函數與巨集定義的區別:
巨集是在預處理時進行的程式碼替換,內聯是在編譯時進行的;
行內函數是真正的函式,只是在呼叫時,沒有呼叫開銷,在編譯階段插入程式碼,像巨集一樣進行展開;
行內函數會進行引數匹配檢查,巨集定義沒有引數匹配檢查。
十一、const和typedef(主要講了const的用處,有那些優點)
1)#define:
巨集不僅可以用來代替常數值,還可以用來代替表示式,甚至是程式碼段。(巨集的功能很強大,但也容易出錯,所以其利弊大小頗有爭議。)
巨集的語法為:
#define 巨集名稱 巨集值
注意,巨集定義不是C或C++嚴格意義上的語句,所以其行末不用加分號結束。
作為一種建議和一種廣大程式設計師共同的習慣,巨集名稱經常使用全部大寫的字母。
利用巨集的優點:
1)讓程式碼更簡潔明瞭
當然,這有賴於你為巨集取一個適當的名字。一般來說,巨集的名字更要注重有明確直觀的意義,有時寧可讓它長點。
2)方便程式碼維護
對巨集的處理,在編譯過程中稱為“預處理”。也就是說在正式編譯前,編譯器必須先將程式碼出現的巨集,用其相應的巨集值替換。所以在程式碼中使用巨集表達常數,歸根結底還是使用了立即數,並沒有明確指定這個量的型別。
2)typedefine:
typedef與#define的區別
typedef則常用來定義關鍵字、冗長的型別的別名,是在編譯時處理的。
巨集定義只是簡單的字串代換(原地擴充套件),而typedef則不是原地擴充套件,它的新名字具有一定的封裝性,以致於新命名的識別符號具有更易定義變數的功能。
typedef (int*) pINT;
以及下面這行:
#define pINT2 int*
效果相同?實則不同!實踐中見差別:pINT a,b;的效果同int *a; int *b;表示定義了兩個整型指標變數。而pINT2 a,b;的效果同int *a, b;
表示定義了一個整型指標變數a和整型變數b。
注意:兩者還有一個行尾;號的區別哦!
3)const:
const部分
常量定義的格式為:
const 資料型別 常量名 = 常量值;
而const定義的常量具有資料型別,定義資料型別的常量便於編譯器進行資料檢查,使程式可能出現錯誤進行排查。常量必須一開始就指定一個值,然後,在以後的程式碼中,我們不允許改變此常量的值。
區別:
1.記憶體空間的分配上。define進行巨集定義的時候,不會分配記憶體空間,編譯時會在main函式裡進行替換,只是單純的替換,不會進行任何檢查,比如型別,語句結構等,即巨集定義常量只是純粹的置放關係,如#define null 0;編譯器在遇到null時總是用0代替null它沒有資料型別.而const定義的常量具有資料型別,定義資料型別的常量便於編譯器進行資料檢查,使程式可能出現錯誤進行排查,所以const與define之間的區別在於const定義常量排除了程式之間的不安全性.
2.const常量存在於程式的資料段,#define常量存在於程式的程式碼段。
3. 有些整合化的除錯工具可以對const常量進行除錯,但是不能對巨集常量進行除錯。
十二、排序演算法有哪些?快速排序怎麼實現的?最好時間複雜度,平均時間複雜度
十三、連結指示:extern “C”(作用)
C++程式有時需要呼叫其他語言編寫的函式,最常見的是呼叫C語言編寫的函式。像所有其他名字一樣,其他語言中的函式名字也必須在C++中進行宣告,並且該宣告必須指定返回型別和形參列表。對於其他語言編寫的函式來說,編譯器檢查其呼叫方式與處理普通C++函式的方式相同,但生成的程式碼有所區別。C++使用連結指示(linkage directive)指出任意非C++函式所用的語言。
宣告一個非C++函式:
連結指示可以有兩種形式:單個或複合。連結指示不能出現在類定義或函式定義的內部。
例如:
單語句:extern "C" size_t strlen(const char *);
複合語句:extern "C" {
int strcmp(const char*, const char*);
char *strcat(char*, const char*);
}
連結指示與標頭檔案:
複合語句:
extern "C" {
#include <string.h>
}
指向extern "C"函式的指標:
編寫函式所用的語言是函式型別的一部分。(指向其他語言編寫的函式的指標必須與函式本身使用相同的連結指示)
extern "C" void (*pf)(int);
當我們使用pf呼叫函式時,編譯器認定當前呼叫的是一個C函式。
指向C函式的指標與指向C++函式的指標是不一樣的型別。
連結指示對整個宣告都有效:
當我們使用連結指示時,他不僅對函式有效,而且對作為返回型別或形參型別的函式指標也有效。
//f1是一個C函式,它的形參是一個指向C函式的指標
extern "C" void f1( void(*)(int) );
因為連結指示同時作用於宣告語句中的所有函式,所以如果我們希望給C++函式傳入一個指向C函式的指標,則必須使用類型別名。
//FC是一個指向C函式的指標
extern "C" typedef void FC( int );
//f2是一個C++函式,該函式的形參是指向C函式的指標
void f2(FC *);
十四、c語言和c++有什麼區別?(大體講了一下,繼承、多型、封裝、異常處理等)
封裝:是面向物件的特徵之一,是物件和類概念的主要特性。封裝,也就是把客觀事物封裝成抽象的類,並且類可以把自己的資料和方法只讓可信任的類或者物件操作,對不可信的進行資訊隱藏。
繼承:使用現有類的所有功能,並在無需重新編寫原來類的情況下,對這些功能進行擴充套件。
繼承過程,是從一般到特殊的過程。
繼承的實現方式有三類:實現繼承、介面繼承和可視繼承。
1) 實現繼承:使用基類的屬性和方法而無需額外編碼的能力。
2) 介面繼承:僅使用屬性和方法的名稱,但是子類必須提供實現的能力。
3) 可視繼承:子窗體實現基窗體的外觀和實現程式碼的能力。
多型:允許將子類型別的指標賦給基類型別的指標。允許將父物件設定成為和一個或更多的他的子物件相等的技術,賦值之後,父物件就可以根據當前賦值給它的子物件的特性以不同的方式運作。
實現多型的兩種方式:覆蓋和過載。
覆蓋:子類重新定義基類虛擬函式的做法。
過載:允許存在多個同名函式,而這些函式的引數列表不同(或許引數個數不同,或者引數型別不同,或者兩者都不同)。
異常處理:主要用於針對程式在執行時刻出現錯誤而提供的語言層面的保護機制。它允許開發者最大限度地發揮,針對異常處理進行相應的修改調整。
C++語言除了提供異常的關鍵字語法支援以外,其標準庫中支援異常處理而封裝異常類也很好的為應用程式中異常處理判斷使用提供直接的幫助。
C++的異常類分別定義在標頭檔案中,如最通用的異常類exception,它只報告異常的發生,不提供任何額外資訊。
1)C++語言中針對異常處理提供了三個關鍵字,分別為try、throw與catch。
異常檢測是採用throw表示式實現的。通常throw關鍵字後會跟隨著一個運算元,該運算元可以是一個表示式、一個C++內建型別資料或者為類型別的物件等。
try
C++面試知識點彙總:
一、多型性:實現了“一個介面,多種方法”。程式在執行時才決定呼叫的函式。
從實現的角度來講,多型可以分為兩類:編譯時的多型性和執行時的多型性。前者是通過靜態聯編來實現的,比如C++中通過函式的過載和運算子的過載。後者則是通過動態聯編來實現的,在C++
一、strcpy函式的編寫?(memcpy函式的編寫)
1)函式原型:extern char *strcpy(char *dest,const char *src);
功能:將src所指由NULL結束的字串複製到dest所指的陣列中。位於string.h標頭檔案裡。
注意: Qt 學習 總結 C魚 自動關聯
第一種自然是手動關聯了,只要調用connect函數就能實現自動關聯。這裏重點講第二種,自動關聯:為了實現槽函數自動進行關聯,對於Qt窗口部件已經提供的信號,可按照以下規範命名:void on_<窗口部件名稱>_<信號名 Qt學習總結(C魚)之路徑參數引用1.引用相對路徑:
例如: QCursor cursor(QPixmap("1.png"));
問題:會發現引用失敗,這是因為相對路徑都是從當前工作目錄開始找起文件的。可以通過以下函數獲取當前工作目錄:
bool QDir::setCurrent ( co
面向物件
1.面向物件和麵向過程的區別
面向過程關注於一個功能實現的步驟,按步驟程式設計實現功能。
面向物件關注於一個功能實現的行為,將一些行為封裝為一個物件來統一呼叫。
面向過程是一種事件為中心的程式設計思想。就是分析出解決問題所需的步驟,然後用函式把這些步 core java:
一、集合
1、hashMap
結構如圖:
HashMap在Map.Entry靜態內部類實現中儲存key-value對。
HashMap使用雜湊演算法。在put和get方法中。它使用hashCode()和equals()方法。當我們通過傳遞key-value對呼叫
一、字串常量
位於一對雙引號中的任意字元,如果字串文字中間沒有間隔或間隔是空格符,ANSI C會將它串起來。例如
char str[50]="hello" "wo" "you!"; 和 char st[50]="wo,nihao!"; &nbs
1120 Friend Numbers
題目翻譯:
如果兩個整數各位數之和相等,那麼這兩個數稱為“friend numbers”,和稱為“friend ID”。例如,123和51就是“friend numbers”,因為1+2+3=5+1=6,6為“fri
主要來自於兩篇文章
https://www.zhihu.com/question/27581780
http://www.oschina.net/translate/hashtable-vs-dictionary?nocache=1492512523856
Map和Dic
注意:輸入的多組輸入,不是一組,已經猜了很多次坑了哦!
輸入
預先不輸入資料的組數
while(cin>>a>>b){
cout<<a+b<<endl;
}
預先知道資料組數
cin>
內部類是一個統稱,具體分為四種:成員類,靜態成員類,區域性類,匿名類。其中匿名類是區域性類的特殊情況。對於成員類和靜態成員類都存在於類的頂層程式碼中。相當於類的靜態方法和非靜態方法的關係。區別在於成員類依賴於類例項而靜態成員類不依賴。所以前者只能訪問例項方法和成員而後者只能訪問靜態方法和成員。它們都用於建立
1、C和C++的特點與區別?
答:(1)C語言特點:
1.作為一種面向過程的結構化語言,易於除錯和維護;
2.表現能力和處理能力極強,可以直接訪問記憶體的實體地址;
3.C語言實現了對硬體的程式設計操
陣列
定義:陣列是有序的並且具有相同型別的資料的集合。
一維陣列
1、一般形式:型別說明符 陣列名[常量表達式];例如: int a[10]; 元素為a[0]----a[9].
2、常量表達式中不允許包含變數,可以包含常量或符號常量。
3、陣列元素下標可以是任何整型常量、整型變數或任何整型表示式。
前言
本人2012屆,廣州某985高校軟體學院本科生一枚,技術方面絕對不能與我班大神們相比。於4月25日正式簽了offer,崗位是後臺開發,想想經過了簡歷篩選,筆試,三輪面試,自己還是挺幸運的,現在就把面試的細節和經歷和大家分享一下。
失敗經歷
從3月開始,聽聞各大公司會開始在學校進行暑期實習
關於面試題 先說說sql面試題吧,來到深圳後,第一天面了兩家公司,sql題出奇的相似,一般都是考的基本函式,例如求平均值,求和,求最大值、最小值等函式,sql關鍵字考的比較多的是disti
線性表
線性表特點
存在一個唯一的一個被稱作”第一個”的資料元素
存在唯一的一個被稱做”最後一個”的資料元素
除第一個之外,集合中的每個資料元素均只有一個前驅
除最後一個之外,集合中每個資料元素均只有一個後繼
定義
一個線性表是n個數據元素的
http://blog.csdn.net/xsl1990/article/details/16359289
每個設計模式詳細介紹請看
http://blog.jobbole.com/tag/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/
初到凡科,是在鳳凰新村地鐵A出口,右拐50米,第一棟建築就是5號樓,首層便是凡科科技。
到了前臺,先說明來意後(通知來面試業務運維的),登記一下基本後,對方便拿出一套筆試題給我做,試題都是關於linux的,感覺挺基礎的,選擇題有考協議、有考工具、也有考命令實現的
C的記憶體基本上分為4部分:靜態儲存區、堆區、棧區以及常量區。他們的功能不同,對他們使用方式也就不同。
1.棧 ——由編譯器自動分配釋放;
2.堆 ——一般由程式設計師分配釋放,若程式設計師不釋放,程式結束時可能由OS回收;
3.全域性區(靜態區)——全域性變數
2018年8月初得螞蟻垂青(本人非985/211,螞蟻真的不是很在乎學歷!!!),有了一次社招機會,前後經歷三關,隨敗北但受益匪淺,在此與各位朋友分享經歷與心得。
第一關:線上筆試
筆試題內容如下:
說明:
構建一個本地快取,快取的物件是使用者ID以及部分使用者的資訊。 相關推薦
面試總結(C++基礎)
網易面試(C++基礎)
Qt學習總結(C魚)之信號與槽01
Qt學習總結(C魚)之路徑參數引用
面試專題(Java基礎)
java面試總結(資料來源網路)
字串、陣列、指標總結(C語言)
PAT甲級題目記錄總結(C++語言)
【面試必讀(程式設計基礎)】雜湊表、Map和字典
牛客網輸入規範總結(c++部分)
JAVA面試總結(待整理)
騰訊研發類筆試面試試題(C++方向)
陣列結構體總結(C語言)
已拿到offer 2015年騰訊暑期實習面試總結(技術崗)
2018年7月Java面試總結(面試題)
線性表總結(c語言)
【面試必讀(程式設計基礎)】幾種常用的設計模式介紹
記——凡科業務運維工程師面試總結(5.10)
【轉】騰訊研發類筆試面試試題(C++方向)
2018螞蟻金服面試總結(Java方向)