1忱反、面向對象與面向過程的區(qū)別是什么铺遂?
面向過程
面向過程就是分析出解決問題所需要的步驟淘讥,然后用函數把這些步驟一步一步實現,使用的時候一個一個依次調用就可以了泻拦;面向對象是把構成問題事務分解成各個對象毙芜,建立對象的目的不是為了完成一個步驟,而是為了描敘某個事物在整個解決問題的步驟中的行為争拐。
可以拿生活中的實例來理解面向過程與面向對象腋粥,例如五子棋,面向過程的設計思路就是首先分析問題的步驟:1架曹、開始游戲隘冲,2、黑子先走绑雄,3展辞、繪制畫面,4万牺、判斷輸贏罗珍,5、輪到白子脚粟,6覆旱、繪制畫面,7核无、判斷輸贏扣唱,8、返回步驟2团南,9噪沙、輸出最后結果。把上面每個步驟用不同的方法來實現已慢。
面向對象
面向對象的設計則是從另外的思路來解決問題曲聂。整個五子棋可以分為1、黑白雙方佑惠,這兩方的行為是一模一樣的朋腋,2、棋盤系統(tǒng)膜楷,負責繪制畫面旭咽,3、規(guī)則系統(tǒng)赌厅,負責判定諸如犯規(guī)穷绵、輸贏等。第一類對象(玩家對象)負責接受用戶輸入特愿,并告知第二類對象(棋盤對象)棋子布局的變化仲墨,棋盤對象接收到了棋子的變化就要負責在屏幕上面顯示出這種變化勾缭,同時利用第三類對象(規(guī)則系統(tǒng))來對棋局進行判定。
可以明顯地看出目养,面向過程是以事件為中心的開發(fā)方法俩由,面向對象是以功能來劃分問題,而不是步驟癌蚁。同樣是繪制棋局幻梯,這樣的行為在面向過程的設計中分散在了多個步驟中,很可能出現不同的繪制版本努释,因為通常設計人員會考慮到實際情況進行各種各樣的簡化碘梢。而面向對象的設計中,繪圖只可能在棋盤對象中出現伐蒂,從而保證了繪圖的統(tǒng)一煞躬。
2、面向對象三大特征饿自?
面向對象方法首先對需求進行合理分層汰翠,然后構建相對獨立的業(yè)務模塊,最后通過整合各模塊昭雌,達到高內聚复唤,低耦合的效果,從而滿足用戶要求烛卧。具體而言佛纫,有三個特征:封裝、繼承和多態(tài)总放。
封裝:
封裝是指將客觀事物抽象成類呈宇,每個類對自身的數據和方法進行保護。類可以把自己的數據和方法只讓可信的對象操作局雄,對不可信進行信息隱藏甥啄。C++中類是一種封裝手段,描述客觀事物的過程是封裝炬搭,本質上是對客觀事物的抽象蜈漓。
繼承:
面向對象編程 (OOP) 語言的一個主要功能就是“繼承”。繼承可以使用現有類的所有功能宫盔,并在無需重新編寫原來的類的情況下對這些功能進行擴展融虽。
通過繼承創(chuàng)建的新類稱為“子類”或“派生類”。被繼承的類稱為“基類”灼芭、“父類”或“超類”有额。繼承的過程,就是從一般到特殊的過程。要實現繼承巍佑,可以通過“繼承”(Inheritance)和“組合”(Composition)來實現茴迁。
繼承概念的實現方式有三類:實現繼承、接口繼承和可視繼承句狼。
- 實現繼承是指使用基類的屬性和方法而無需額外編碼的能力笋熬;
- 接口繼承是指僅使用屬性和方法的名稱、但是子類必須提供實現的能力腻菇;
- 可視繼承是指子窗體(類)使用基窗體(類)的外觀和實現代碼的能力。
多態(tài)
多態(tài)是指一個類實例的相同方法在不同情形有不同表現形式昔馋。多態(tài)機制使具有不同內部結構的對象可以共享相同的外部接口筹吐。這意味著,雖然針對不同對象的具體操作不同秘遏,但通過一個公共的類丘薛,它們(那些操作)可以通過相同的方式予以調用。
3邦危、面向對象五大原則洋侨?
單一職責原則SRP(Single Responsibility Principle)
是指一個類的功能要單一,不能包羅萬象倦蚪。如同一個人一樣希坚,分配的工作不能太多,否則一天到晚雖然忙忙碌碌的陵且,但效率卻高不起來裁僧。
開放封閉原則OCP(Open-Close Principle)
一個模塊在擴展性方面應該是開放的而在更改性方面應該是封閉的。比如:一個網絡模塊慕购,原來只服務端功能聊疲,而現在要加入客戶端功能,
那么應當在不用修改服務端功能代碼的前提下沪悲,就能夠增加客戶端功能的實現代碼获洲,這要求在設計之初,就應當將服務端和客戶端分開殿如,公共部分抽象出來贡珊。
替換原則(the Liskov Substitution Principle LSP)
子類應當可以替換父類并出現在父類能夠出現的任何地方。比如:公司搞年度晚會握截,所有員工可以參加抽獎飞崖,那么不管是老員工還是新員工,
也不管是總部員工還是外派員工谨胞,都應當可以參加抽獎固歪,否則這公司就不和諧了。
依賴原則(the Dependency Inversion Principle DIP)
具體依賴抽象,上層依賴下層牢裳。假設B是較A低的模塊逢防,但B需要使用到A的功能,這個時候蒲讯,B不應當直接使用A中的具體類: 而應當由B定義一抽象接口忘朝,并由A來實現這個抽象接口,B只使用這個抽象接口:這樣就達到了依賴倒置的目的判帮,B也解除了對A的依賴局嘁,反過來是A依賴于B定義的抽象接口。
通過上層模塊難以避免依賴下層模塊晦墙,假如B也直接依賴A的實現悦昵,那么就可能造成循環(huán)依賴。一個常見的問題就是編譯A模塊時需要直接包含到B模塊的cpp文件晌畅,而編譯B時同樣要直接包含到A的cpp文件但指。
接口分離原則(the Interface Segregation Principle ISP)
模塊間要通過抽象接口隔離開,而不是通過具體的類強耦合起來
4抗楔、什么是深拷貝和淺拷貝棋凳?
如果一個類擁有資源(堆或者是其他系統(tǒng)資源),當這個類的對象發(fā)生復制時连躏,資源重新分配剩岳,這個過程就是深拷貝;反之對象存在資源反粥,但復制過程并未復制資源的情況稱為淺拷貝卢肃。
程序中,應避免淺拷貝才顿,否則容易導致對同一資源的多次釋放莫湘。
5、類成員變量的初始化順序與聲明順序相同嗎郑气?
在C++中幅垮,類的成員變量的初始化順序只與變量在類中的聲明順序有關,與構造函數的初始化列表無關尾组。而且靜態(tài)成員變量先于實例變量忙芒,父類成員變量先于自雷成員變量。初始化順序與變量在內存中的次序有關讳侨,而內存中變量的排序呵萨,早在編譯器就根據變量的定義次序確定了。
6跨跨、不能被繼承的類如何設計潮峦?
將構造函數設為private可以阻止一個類被實例化以及被繼承囱皿。
方法一:將構造函數設為私有函數。通過共有函數可以向外傳遞實例忱嘹。但是所有實例都在堆上嘱腥,需要程序員手動釋放。
class finalClass1{
public:
static finalClass1* get(){
return new finalClass1;
}
static void free(finalClass1* pInstance){
delete pInstance;
pInstance = nullptr;
}
private:
finalClass1(){}
~finalClass1(){}
};
方法二:由于友元可以訪問類的私有成員拘悦,可通過友元函數的性質齿兔,做如下實現:
template<typename T> class MakeFinal{
friend T;
private:
MakeFinal(){}
~MakeFinal(){}
};
class finalClass2:virtual public MakeFinal<finalClass2>{
public:
finalClass2(){}
~finalClass2(){}
}
finalClass2是不可繼承的類,并且它可以在堆和棧上自由創(chuàng)建础米。當它繼承時分苇,其子類將跳過finalClass2訪問MakeFinal的私有構造函數,編譯器將報錯椭盏。
7组砚、多態(tài)的分類?
多態(tài)分為兩種:通用的多態(tài)和特定的多態(tài)掏颊。兩者的區(qū)別是前者對工作的類型不加限制,允許對不同類型的值執(zhí)行相同的代碼艾帐;后者只對有限數量的類型有效乌叶,而且對不同類型的值可能要執(zhí)行不同的代碼。
通用的多態(tài)又分為參數多態(tài)(parametric)和包含多態(tài)(inclusion)柒爸;特定的多態(tài)分為過載多態(tài)(overloading)和強制多態(tài)(coercion)准浴。
強制多態(tài)
編譯程序通過語義操作,把操作對象的類型強行加以變換捎稚,以符合函數或操作符的要求乐横。程序設計語言中基本類型的大多數操作符,在發(fā)生不同類型的數據進行混合運算時今野,編譯程序一般都會進行強制多態(tài)葡公。程序員也可以顯示地進行強制多態(tài)的操作(Casting)。
舉個例子条霜,比如催什,int+double
,編譯系統(tǒng)一般會把int轉換為double
宰睡,然后執(zhí)行double+double
運算蒲凶,這個int->double
的轉換,就實現了強制多態(tài)拆内,即可是隱式的旋圆,也可顯式轉換。過載(overloading)多態(tài)
同一個名(操作符﹑函數名)在不同的上下文中有不同的類型麸恍。程序設計語言中基本類型的大多數操作符都是過載多態(tài)的灵巧。通俗的講法,就是C++中的函數重載。參數多態(tài)
采用參數化模板孩等,通過給出不同的類型參數艾君,使得一個結構有多種類型。例如肄方,模板類冰垄。包含多態(tài)
同樣的操作可用于一個類型及其子類型(注意是子類型,不是子類)权她。包含多態(tài)一般需要進行運行時的類型檢查虹茶。例如,虛函數virtual---override
機制
8隅要、C++中如何實現多態(tài)蝴罪?
C++中多態(tài)是主要通過虛函數實現的。虛函數的本質是通過基類訪問派生類定義的函數步清。每個含虛函數的類要门,其實例對象內部都有一個虛函數表指針,位于實例首部廓啊。該指針被初始化為指向本類虛函數表的內存地址欢搜。不管對象類型如何變化,該類對象顳部的虛函數表指針時固定的谴轮,因此能夠動態(tài)地實現多態(tài)調用炒瘟。
9、虛函數使用時注意事項第步?
僅列舉容易出錯的幾項:
- 1疮装、聲明中virtual關鍵字即可,在類外不需要粘都,也不能使用virtual關鍵字廓推。
- 2、非類成員函數驯杜,內聯函數受啥、全局函數、類成員函數中靜態(tài)成員函數和構造函數都不能定義為虛函數鸽心。但很有必要將析構函數定義為虛函數滚局,否則delete指向派生類的基類指針時,將只調用基類析構函數顽频,造成內存泄漏藤肢。
- 3、構造函數里可以調用虛函數糯景,由于基類構造函數調用虛函數時嘁圈,子類還未構造省骂,因此將調用基類自身的版本。子類構造函數中調用虛函數最住,同樣是調用子類自身的版本钞澳。
- 4、使用虛函數需要維護虛函數表涨缚,產生額外的系統(tǒng)開銷轧粟。如果是很小的類,且不需要派生其他類脓魏,則沒有必要定義虛函數兰吟。