面試題(1)

  • C++的基礎數據類型分爲3種:整數型、浮點型和void型
  • 除了指針類型與long隨操作系統字長變化而變化外,其他的都固定不變(32位和64相比)
  • 表示整數、字符和布爾值的算術類型合稱爲整形,整形根據修飾符細分爲13種形式,它們的區分主要體現在類型名、長度和表示範圍幾個方面。
  • C++常量:常量是不可改變的數據,主要分爲整形常量,浮點型常量,字符型常量,字符串常量,轉義字符常量(’\0nnn’),地址常量
  • 常量和變量的區別:常量是不可以改變值的量,變量是可以改變值的量,常量在定義時必須初始化,變量可以在定義時不初始化。常量本身沒有地址屬性(除字符串常量等),不可以尋址,變量可以尋址。常量有相對較高編譯執行效率。

  • 哪些操作符?:表達式是由操作符、操作數字和標點符號組成的序列;按照功能區分:算術、關係、邏輯、位、賦值、自增和自減,條件,sizeof和逗號操作符;按照操作數:一元、二元和三元操作符

  • 操作符優先級對運算結果的影響:優先級決定了表達式的運算順序,不同優先級的運算符的不同使用會影響表達式的運算結果
  • 邏輯操作符:邏輯操作只返回true或false這兩種值,它們可以用來做判斷條件,邏輯操作符不會改變操作數的值。
  • 自增自減前操作與後操作的區別:前自增自減操作的優先級大於賦值運算符,而後自增自減的優先級小於賦值運算符,後自增自減操作後表達式的值不會發生改變
  • 指針自增自減的不同:變量的自增自減是修改變量的值,指針的自增自減是修改指針的指向地址

  • 什麼是左值和右值:變量是左值,可以出現在賦值語句的左邊或右邊,也就是說左值可以當右值使用;數字字面量是右值,不能出現在賦值語句的左邊,不能被賦值

  • 什麼是變量:變量是一段實際連續存儲空間的別名,程序中通過變量來申請並命名存儲空間,通過變量的名字可以使用存儲空間
  • 變量的初始化方式:C++支持兩種初始化變量的形式即賦值初始化和直接初始化(把初始化值放在括號中)。如果變量在定義的時候沒有被初始化(局部變量,靜態局部變量,全局變量)
  • 變量默認初始化有什麼規則:系統有時候會自動初始化未初始化的變量。使用未初始化的變量是常見的程序錯誤,建議每個內置類型的對象都要初始化。
  • 什麼是變量的聲明和定義:C++區分了聲明和定義。定義和聲明有相同的時候,但聲明的主要目的是表明變量的類型和名稱,而定義的主要目的是爲變量分配存儲空間,還可以給變量初始化
  • C++中有哪幾種作用域:作用域用於區別變量名的不同有效範圍,分爲全局作用域,局部作用域和語句作用域(for語句內的i)
  • 局部變量與嵌套的作用域:局部變量就是具有局部作用域的變量。在C++中,作用域是可以嵌套的(定義在全局作用域的變量名可以在局部作用域中使用)
  • 變量有哪幾種存儲類型:自動類型變量(auto),靜態類型變量(static),寄存器類型變量(register),外部類型變量(extern)

  • 什麼是引用:引用是變量的別名,主要用作函數的形參來使用

  • const引用和非const引用:const引用是指向const對象的引用,const引用必須被定義爲const類型(const int a = 100;const int& refa = a; );const引用讓變量擁有隻讀屬性
    這裏寫圖片描述

  • C與C++的區別:C語言是結構化的編程語言,它是面向過程的,考慮的是實現過程;C++是面向對象的,考慮的是整個程序模型

  • 匈牙利命名法是一種編程時的命名規範,主要思想是在變量和函數名中加入前綴以增進對程序的理解
  • 變量命名規則:變量名由字母、數字和下劃線組成並且需以字母或下劃線開頭,變量名不可以與保留關鍵字和標準庫衝突

  • 條件語句的幾種形式:if,if…else和if…else if..else

  • 條件語句如何嵌套?如何匹配else子句:條件語句可以在不同的執行語句作用域內進行嵌套,else子句通過{}劃分作用域來實現匹配

  • for循環語句的計算順序:先從左至右執行循環條件語句,如果循環條件語句的判斷語句爲true,則在循環條件語句執行之後繼續執行一次循環執行語句,然後再回到循環條件語句;如果循環語句判斷條件爲false,則停止循環

  • while和do…while的區別:如果循環條件語句爲false,while語句不會執行循環,而do…while保證循環體執行一次
  • 典型循環語句:包括for循環語句,while循環語句和do_while循環語句;for循環語句更多的用於需要遍歷的情況,而while和do-while循環語句可以用於狀態判斷並且根據狀態執行操作等
  • break和continue的區別:continue語句只能出現在循環語句中,而break語句可以出現在switch語句中,continue語句不會退出循環,只會終止本次循環並進入下一次循環,break語句會退出循環語句
  • switch語句的執行順序:如果表達式與其中一個case標號的值匹配,則程序將從該標號後面的第一個語句開始依次執行各個語句,直到switch結束或遇到break語句爲止。如果沒發現匹配的case 標號,則在存在default語句時執行default語句,否則程序從switch語句後面的第一條語句繼續執行。
  • 如何在switch語句定義變量:在switch結構中可以在最後一個case標號或default標號後面定義變量,或者引入塊語句來定義變量。
  • 什麼是遞歸:一個過程或函數直接或間接調用自己本身,叫遞歸過程或遞歸函數;它通常把一個大型複雜的問題層層轉化爲一個與原問題相似的規模較小的問題來求解
  • 漢諾塔問題:程序設計中的經典遞歸問題

  • 實際上,在內存中爲每個數據流開闢一個內存緩衝區,是用來存放流中的數據。流是與內存緩衝區相對應的。

  • 什麼是標準輸入輸出流:標準輸入流是從標準輸入設備(鍵盤)流向程序的數據;標準輸出流是流向標準輸出設備(顯示器)的數據
  • 在C++語言中,數據的輸入和輸出包括對標準輸入設備鍵盤和標準輸出設備顯示器(標準I/O)、對在外存磁盤上的文件(文件I/O)和對內存中指定的字符換存儲空間進行輸入輸出(串I/O)這3個方面。
  • 重載在同一個作用域爲一個給定函數名稱提供多種定義。編譯器根據調用該函數的參量選擇合適的函數或運算符版本

文件輸入/輸出

  • 3種流對象可以用來處理文件:ifstream、ofstream和fstream。
  • 如何讀取一個文件:在C++中,讀取文件使用iostream頭文件內的相關方法。iostream是fstream的基類
  • 文件輸入輸出有哪幾種方式:C++定義了ifstream、ofstream和fstream3種類型以用來支持文件的輸入輸出這裏寫圖片描述

異常與錯誤

  • 什麼是異常:異常就是程序運行時出現的不正常,它可能會導致系統無法正常運行甚至停止運行等嚴重情況,編程者需要實現好的異常處理來保證程序的穩定性
  • 如何拋出和捕捉異常:在C++中,系統通過try塊和異常處理構成了異常機制:其中通過catch語句來捕捉運行時的異常,並且執行異常處理,通過throw語句可以拋出異常

預處理以及內存管理

3種預處理功能:宏定義、文件包含和條件編譯
- 宏定義與操作符的區別:宏定義是C++的預處理命令之一,它是一個替換操作,不做計算和表達式求解,不佔用內存和編譯時間

# (stringizing)字符串化操作符。其作用是:將宏定義中的傳入參數名轉換成用一對雙引號括起來參數名字符串。其只能用於有傳入參數的宏定義中,且必須置於宏定義體中的參數名前

#define  example(str)  #atr
string str = example(abc); ==》 string str = "abc";      

- 宏定義如何展開:用宏定義時設計的宏體去代替宏指令名,並且用實際參數一一取代形式參數

  • include有哪幾種使用方式?什麼區別?:兩種使用方式,#include<>是使用標準頭文件,#include“是使用自定義頭文件”
  • 包含頭文件時如何查找頭文件:標準頭文件在系統文件目錄下查找;用戶自定義文件會依次在用戶目錄,C++安裝目錄和系統文件中查找
  • 如何分配和釋放存儲空間:C++中使用new和delete來分配和釋放存儲空間

虛函數和純虛函數

  • 虛函數和純虛函數的區別:純虛函數是虛函數的一個子集,用於抽象類,含有純虛函數的類就是抽象類,它不能生成對象
  • 如何使用純虛函數:純虛函數用來定義沒有意義的實現,用於抽象類中需要交給派生類具體實現的方法

指針

  • 什麼是指針:指針是用來存儲內存地址的變量,它指向單個對象的地址,除了void指針類型以外,指針的數據類型與所指向地址的變量數據類型必須保持一致
  • 如何初始化指針並對其賦值:指針的初始化就是給指針賦初值,&符號可以用來獲取對象的內存地址,並且賦值給指針變量。指針變量的初始化和賦值都可以通過運算符“=”來實現
  • 是否可以確定指針指向一個對象:指針用於指向對象,一個指針只指向一個對象的內存地址
  • 如何使用指針操作數組:C/C++中,指針對於數組的操作是通過將數組的地址,通常是第一個數組元素的地址賦值給指針來進行操作的。
  • const對象的指針和const指針的區別:const指針的值不可以被修改,但是可以使用該指針修改它所指向對象的值;指向const變量的指針不可以修改所指向的const變量的值,但是自身可以被修改。
    不可以使用(void*)指針保存const對象的地址,而必須使用(const void*)類型的指針來保存const對象的地址
  • 數組指針和指針數組的區別:數組指針是一個指針變量,它指向一個數組。而指針數組是一個只包含指針元素的數組,它的元素可以指向相同類型的不同對象。

  • 函數指針以及如何使用:函數指針就是指向函數的存儲空間地址的指針。可以對函數指針進行賦值並且通過函數指針來調用函數

  • 指針函數和函數指針的區別:函數指針是一個指向函數的指針,它的本質是一個指針;而指針函數只是說明它是一個返回值爲指針的函數,它的本質是一個函數

  • 什麼是this指針:在調用成員函數時,編譯器會隱含地插入一個參數,這個參數就是this指針。this指針指向當前對象本身,表示當前對象的地址

  • 何時使用this指針:當對一個對象調用成員函數時,編譯程序先將對象的地址賦給this指針,然後調用成員函數,每次成員函數存取數據成員時,隱含地使用this指針,而通常不去顯式地使用this指針來引用數據成員

引用與值傳遞

  • 什麼是值傳遞:值傳遞將要傳遞的值作爲一個副本傳遞,在函數調用時,實參把它的值傳遞給對應的形參,形參值的改變不影響實參。
  • 引用與值傳遞的區別:值傳遞傳遞的是一個值的副本。函數對形參的操作不會影響實參的值,而引用傳遞傳遞的是引用對象的內存地址,函數對形參的操作會影響實參的值,實參的值將會隨着形參值得更改而同樣進行更改
  • 指針和引用的區別:
    • 指針是一個實體(所指變量的內存地址),而引用僅是一個別名
    • 引用使用時無需解引用,指針需要解引用
    • sizeof引用得到的是所指向的變量(對象)的大小,而指針得到的是指針本身的大小
    • 引用定義時必須要初始化,不能爲空,指針可以爲空

面向對象與類

  • 面向對象與面向過程的區別:面向過程是一種以過程爲中心的編程思想,以算法進行驅動。面向對象是一種以對象爲中心的編程思想,以消息進行驅動。面向過程編程語言的組成爲:程序=算法+數據,面向對象編程語言的組成爲:程序=對象+消息
  • 面向對象的特徵:封裝(目的是增強安全性和簡化編程,使用者不必瞭解具體的實現細節,而只是通過外部接口或特定的訪問權限使用類的成員)、繼承(可以使用現有類的所有功能,在無需重新編寫原來的類的情況下對這些功能進行擴展)、多態(根據實際的對象類型決定函數調用的具體目標)。面向對象中所有的對象都可以歸屬爲一個類

類是對某種類型的對象定義變量和方法的原型。它表示對現實生活中一類具有公共特徵的事物的抽象。
- C++類和結構的區別:
- C中的結構體和C++中的結構體的不同:C中只能定義數據類型,不允許有函數,而C++中可以定義成員函數,以及public,protected和private數據成員,可以從別的類繼承,可以有虛函數
- 不同之處:結構體中默認訪問權限是public,而類中的是private
- 抽象類及它的用途:包含純虛函數的類稱爲抽象類,抽象類把有共同屬性或方法的對象抽象成一個類

類成員

  • 成員變量有哪些訪問方式:根據訪問權限有private、protected和public3種訪問方式
  • 成員變量有哪些訪問控制方式:通過聲明private、protected和public3種訪問權限來對成員變量進行訪問控制
  • 如何訪問靜態成員:使用靜態數據成員可以節省內存,因爲它是所有對象所共有的;類的靜態成員是可以獨立訪問的,不需要創建類的實例(對象)就可以訪問靜態成員,也不能用實例(對象)來進行調用。類的靜態函數只能調用靜態成員,因爲靜態函數不包含this指針。

多態
多態允許將子類類型的指針賦值給父類類型的指針
- 什麼是多態?多態的作用:多態是面向對象編程的核心概念之一,多態技術允許將父類設置成和它的一個或更多的子對象相等
- C++中如何實現多態?:編程者常說的多態指的是動態多態,它是基於繼承機制和虛函數來實現的。

繼承

  • 派生類和基類的轉換:派生類總是可以轉換爲基類的引用類型(總是合法和自動的)。基類轉換爲派生類需要在確定安全的清下,使用強制轉換來進行轉換(基類是不會自動轉換爲派生類的,因爲基類對象只能是基類對象,它不能包含派生類成員)
  • 什麼是虛成員?有什麼作用:在C++中,虛成員也被稱爲虛函數,虛函數是用於面向對象中實現多態的機制。它的核心理念就是通過基類訪問派生類定義的函數;虛函數的作用是實現動態聯編,當程序發現函數名前的關鍵字virtual後,會自動將其作爲動態聯編處理,即在程序運行時動態的選擇合適的成員函數
  • 構造函數和析構函數的調用時機:構造函數和析構函數的調用時自動進行的。建立對象時會調用構造函數,而銷燬對象時調用析構函數

訪問控制

繼承是指一個對象直接使用另一對象的屬性和方法;繼承可以使子類具有父類的各種屬性和方法
- 有哪幾種繼承方式:公有繼承、保護繼承和私有繼承
- 繼承時訪問級別如何變化:
- public(公有繼承):基類成員保持自己的訪問級別
- protected(保護繼承):基類的public和protected成員在派生類中爲protected成員;基類的private成員保持爲private
- private(私有繼承):基類的所有成員在派生類中爲private成員

1、覆蓋函數和被覆蓋函數只有函數體不同,其函數名、參數列、返回值類型必須同父類中的相對應被覆蓋的函數嚴格一致
2、覆蓋的特徵爲在不同的範圍中(分別位於派生類與基類)的函數,函數名、函數參數,基類必須有virtual關鍵字
- 什麼時候發生函數覆蓋:在繼承時派生類對於抽象類或者接口聲明的方法的具體實現時發生
- 如何訪問基類的成員:派生類中的成員函數可以直接訪問基類中的public和protected成員,但不能訪問基類的private成員。通過派生類的對象只能訪問基類的public成員

複製構造函數

在C++中,類除了提供默認構造函數和析構函數外,編譯器還提供一個默認複製構造函數。每當創建對象的複製時,都將調用複製構造函數

  • 深拷貝和潛拷貝:

    • 淺拷貝(內存地址的複製):指的是在對象複製時,只是對對象中的數據成員進行簡單的複製,如果對象中存在指針,並且沒有自定義拷貝構造函數,使用編譯器默認的拷貝構造函數,淺拷貝就會出現問題(釋放同一個內存空間2次,導致內存泄漏);
    • 深拷貝(值的拷貝,內存地址不同):針對成員變量存在指針的情況,不僅僅是簡單的指針複製,而是重新分配內存空間
  • 什麼是拷貝構造函數:

    • 一個對象以值傳遞的方式傳入函數體
    • 一個對象以值傳遞的方式從函數返回
    • 一個對象需要通過另外一個對象進行初始化

類型轉換構造函數

類型轉換構造函數可以將其他類型直接轉換爲類的對象。
- 類型轉換分類:隱式轉換和顯式轉換
- 什麼是類型轉換構造函數:一個類的構造函數只有一個參數,而且這個參數不是該類的類型而是其他類型

函數

  • 什麼是函數:函數由函數名、參數、返回值類型以及一組包含操作語句的語句塊組成。函數支持重載,程序是由函數組成的
  • 形參和實參區別:形參是函數定義或聲明時的函數形式參數,形參表制定了函數參數的個數和數據類型,實參是函數調用時傳遞給函數的參數,傳遞時要與形參一一對應
  • C++支持參數個數不確定的函數嗎:C++可以通過隱藏參數機制來支持參數個數不確定的函數
  • 什麼是內聯函數:在類聲明的內部聲明或定義的成員函數叫做內聯函數。引入內聯函數的目的是解決函數調用的效率問題。一般來說,內聯機制適用於只有幾行的小的而且經常被調用的函數

函數參數的傳遞

  • 引用形參和非引用形參的區別:把引用變量當成形參傳遞就是引用形參,由於引用變量指向的是同一個內存地址,實際上傳遞的是變量的地址;引用形參把對變量的操作,隱式地轉成通過變量地址來對變量操作
  • 使用引用形參的問題: 調用非const類型的引用形參,實參必須不是const類型,而且實參的類型和形參的類型應當一致;調用一個const引用的形參的函數時,如果實參不是一個變量或者類型不匹配時,函數會創建一個無名的臨時變量用來存儲實參的值,並把這個形參作爲該臨時變量的引用
  • 指針形參和引用形參的區別:函數的形參可以是指針,此時將複製實參指針。與其他非引用類型的形參一樣,該類形參的任何改變僅作用於局部副本,主調函數使用的實參指針的值沒有改變;引用形參實際傳遞的是變量的地址,主調函數的實參的值會跟隨被調函數引用形參的改變而改變

類成員函數

  • 什麼是類成員函數?有哪些特別的類成員函數:類成員中的函數就是類的成員函數;構造函數和析構函數
  • 什麼是靜態函數?如何使用:靜態函數是使用static修飾符修飾的函數,靜態函數沒有this指針,只能訪問靜態變量。在類中如果函數調用的結果不會訪問或者修改任何對象數據成員,這樣的成員聲明爲靜態成員函數比較好
  • 靜態函數能訪問類的私有成員:靜態函數只能直接訪問類的靜態私有成員,靜態函數不可以直接訪問類的非靜態私有成員
  • 一個類可以訪問另一個類的私有成員嗎:類的私有成員是不可以被外部類訪問的,但是外部類可以使用宏定義等特殊方法來實現訪問類的私有成員

函數重載

  • 函數重載與作用域:函數重載是指在相同的作用域中,具有相同函數名而形參列表不同的多個函數。
    • 如果局部地聲明一個函數,則該函數將屏蔽而不是重載在外層作用域中聲明的同名函數
  • 函數重載的匹配:編譯器遇到對重載函數的調用時,必須確定調用哪個函數。如果沒能找到參數完全匹配的函數,則找一個替代函數。此時編譯器將函數調用的實參與所有重載函數的參數比較,這一過程成爲參數匹配
  • 函數重載時如何實現實參的類型轉換:在函數重載匹配時,先通過標準轉換來實現匹配,如果不行,再通過類類型轉換來實現匹配

模板和STL

  • 什麼是函數模板:是使用模板技術定義了參數化類型的非成員函數,這使得程序能夠使用不同的參數類型調用相同的函數
  • 什麼是類模板:類模板是使用模板技術的類,描述了能夠管理其他數據類型的通用數據類型。類模板技術通常用於建立包含其他類型的容器類,例如隊列、鏈表和堆棧等
    • 調用時需要明確指出使用何種數據類型,而不能由編譯器自行指定

容器

  • 什麼是容器:容器是容納特定類型對象的集合,在STL中,有順序容器和關聯容器
    • 順序容器:指的是將一組相同類型T的對象,以嚴格的線性形式組織在一起;順序容器可以視爲數組和鏈表的擴展:vector、deque、list
      • vector是一種順序容器,存放的元素是以連續的數組的方式存儲的,可以通過v[i]的方式訪問vector裏面的元素;對特定值的訪問,只能通過遍歷vector的方式進行比較,對vector插入或者刪除元素時,需要保持元素的連續性,相對來說性能較低
      • vector是一種容器,那麼可以向vector’添加一個數據。push_back():表示將數據添加到vector尾部,並按需分配內存
      • 訪問vector中的數據有如下兩種方法:vector::at()和vector::operator[];at()是首選,at()進行了邊界檢查,如果訪問超過了vector的範圍,將拋出一個異常,operator[]則不會
    • deque容器是一個雙端隊列,存放的數據不是以連續的形式存放的
    • list容器:一種鏈表的實現,存儲的元素是通過使用雙向鏈表實現的;其優勢在於在list的任意位置插入和刪除,非常快速。但是list在查找和隨機存取時需要更大的開銷
  • 什麼是迭代器的範圍(迭代器是STL提供的對一個容器中對象的訪問方法):迭代器有兩個可以通過容器的begin()操作和end()操作獲取。其中begin指向容器中的第一個元素,end指向的是容器中的最後一個元素的下一個位置,也就是說end所指向的並不是容器的元素。通常begin和end之間的範圍就是迭代器的範圍

    使用迭代器對容器進行遍歷
    vector<int> v;
    v.push_back(2);
    v.push_back(1);
    vector<int>::iterator first = v.begin();
    while(first != v.end())
    {
        int  i = *first;
        first++;
    

    }

  • 什麼是關聯容器:能夠通過鍵值(關鍵字)來查找和讀取元素的容器。在STL中有4個關聯容器:map、set、multimap和multiset容器

    • map的元素是“鍵-值”對的二元組形式即鍵用作元素在map中的索引,值表示所存儲和讀取的數據。set和map類型的對象所包含的元素具有不同的鍵,如果需要一個鍵對應多個實例,則需要使用multimap或multimap類型
    • set是一個容器,它其中所包含的元素的值是唯一的。集合中的元素按一定的順序排列,並被作爲集合中的實例。一個集合通過一個鏈表來組織,在插入操作和刪除操作上比vector快,但查找或添加末尾的元素時會有些慢

泛型編程

  • 什麼是泛型編程:以獨立於(不考慮)任何特定類型的編程方式,針對不同的類型提供通用的實現
  • C++如何實現泛型編程:使用C++中的模板技術來實現的,主要包括函數模板和類模板
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章