1、都說c++是面向對象的語言,面向對象的三個特性能 [展開] 介紹一下嗎?
封裝:封裝是一種集中管理的思想,把內部的數據和實現方法組合在一起,并且不對外暴漏內部的數據和實現方法,只對外提供幾個接口來完成函數的調用和數據的操作,保證了數據的安全性和一致性。
繼承:繼承是指一個類可以繼承另一個類的方法和數據,可以提高代碼的復用性,建立類與類之間的關系。
多態:多態是指同一個方法對于不同的對象有不同的行為,提高了代碼的靈活度。
2、多態的底層實現有了解過嗎?
多態的底層是通過一個虛函數指針實現的,虛函數指針指向一塊虛函數表,虛函數表當中存儲的各個函數的地址,虛函數表是一個指針數組,虛函數表中存儲的是函數指針,當一個表達式滿足多態的時候,它確定類型的時候就不是在編譯階段,而是在運行階段來判斷是什么類型,然后根據不同的對象來調用虛函數表。
3、虛函數它底層又是怎么實現的?
當一個類中的函數被
virtual
修飾之后,就會多出一個虛函數指針,虛函數指針指向虛函數表。
4、(場景一)有兩個類它們的實例變量以及它們支持的函數方法完全相同,一個類實現了一個虛函數,它們有什么區別?它們生成一個實例對象的內存占用一樣嗎?
占用內存不一樣,實現了虛函數就會多一個虛函數指針,會多出4/8字節的空間,內存占用不同。
5、(場景二)有四個類 B、C 繼承 A,D 繼承 B、C(多繼承),A 中有一個 public 函數,然后 B、C 里面各自重寫了,然后從 D 里面想要調用 B 或則 C 的實現要怎么調用呢?
直接用類域操作符
::
,指定類域調用。
6、還是上述的場景,A 里邊有一個 public 變量,B、C 是繼承自 A 的,D 繼承自 B、C,那么 D 里邊又存儲了幾份 public 變量(一直在引導我,是一份、兩份、三份)
這題需要分類討論。
普通繼承:兩份(B、C當中各自一份)。
虛繼承:一份,直接放在公共區。
7、malloc 跟 new 有什么區別呀?
1、malloc返回類型是(void*)需要手動強制類型轉換。
2、malloc內存分配錯誤返回
NULL
,而new是拋異常。3、new分配內存的同時會調用構造函數進行初始化,malloc需要手動初始化。
4、malloc分配內存的時候需要手動計算開多大的空間,new不需要。
5、new釋放內存使用delete,malloc使用free。
6、new的底層也是去調用
operator new
,在operator new
當中也是調用malloc來實現內存分配的。
8、new 除了分配內存它還會比 malloc 還有其他額外的操作嗎?
會調用構造函數進行初始化。
9、new 實際上是做了兩件事嘛,一個是分配內存、一個是調用實例的構造函數,那有了解過 new 可以只進行一個操作嘛?比如只分配內存不調用構造函數、或者只調用構造函數不分配內存嘛?
不分配內存,只調用構造函數:定位new(
placement new
)以及operator new
。不調用構造函數,只分配內存:
new (std::nothrow) type
。
10、計算下面兩個結構體的sizeof是多少
struct {char A;char B;int C;
}struct {char A;int C;char B;
}
內存對齊問題。
第一個是8字節。
第二個是12字節。
11、看你寫了對STL熟悉,那智能指針你有了解過嘛?
1、最早期的智能指針是
auto_ptr
,但這種智能指針并沒有完全實現了指針的功能,主要是實現了RAII
的思想,以及權限轉移。2、然后出現了
unique_ptr
,這個智能指針的做法比較粗暴,不讓拷貝,禁止調用拷貝構造。3、然后就是
shared_ptr
,這個智能指針解決了原來的問題:一塊地址只能被一個智能指針指向,否則就會導致同一塊內存被釋放兩次。解決方法:利用引用計數。但依舊存在循環引用的問題。4、
weak_ptr
,一個輔助性質的智能指針,用于解決循環引用的問題,讓內部的指針變量用weak_ptr
來表示,weak_ptr
不會修改引用計數,所以能夠很好的解決循環引用的問題。
12、舉一個實際場景智能指針的例子?為什么用?怎么使用的?不用可以嘛?
在關于異常安全的時候就最好用智能指針。
比如以下代碼:
#include<iostream> using namespace std;int div() {int a, b;cin >> a >> b;if (b == 0)throw invalid_argument("除0錯誤");return a / b; } void Func() {// 1、如果p1這里new 拋異常會如何?// 2、如果p2這里new 拋異常會如何?// 3、如果div調用這里又會拋異常會如何?int* p1 = new int;int* p2 = new int;cout << div() << endl;delete p1;delete p2; } int main() {try{Func();}catch (exception& e){cout << e.what() << endl;}return 0; }
不使用智能指針,就會導致各種內存沒有被釋放,或者直接沒有開空間的問題。
可以不用指針指針嗎?可以,但是需要套好幾層異常捕捉,太麻煩,代碼的可讀性也變得很低了。
13、剛才你提到了shared_ptr 底層是用一個引用計數來實現的共享,那還了解過其他的內存管理方式嘛?
JAVA中的內存自動回收機制,是通過比較復雜的一套算法來計算回收的時機,具體沒有深入了解。
14、STL 里邊常用的 vector 容器的擴容機制有了解過嘛?
擴容機制在不同平臺不一樣。
VS:1.5倍。
Linux:2倍。
擴容是重新開一片空間,然后把原來的內容拷貝過來,再銷毀原來的空間。
15:擴容3倍可以嘛?
可以,但是可能會導致大量的空間浪費。
16:vector 的初始容量了解過嘛?什么時候會進行初次擴容?
在第一次添加元素的時候會進行擴容,第一個擴容一般會設置為8或者16。