C++ 的基礎概念(3)——多態詳解。

最近兩次面試都問到了多態,我也不得不重視起來了,最近最大的收獲就是:基礎知識很重要,就算你很會寫代碼,但是面試官問你基礎知識答不上來的話,也很難被人賞識和錄用,所以還是要多補補基礎概念,這一篇就說多態。

之前第一篇提到過,多態是指同樣的消息被不同的對象接受時導致不同的行為。分四類:重載多態,強制多態,包含多態參數多態

多態從實現的角度分為 編譯時多態 運行時多態。不同處就是確定操作針對的具體對象的時間是編譯的時候還是運行的時候。

重載多態:

我們知道的普通函數及類的成員函數的重載都屬于重載多態。

函數的重載因為很常用相信一般都很熟悉了,就是指函數名相同而形參的個數和類型不同,編譯器調用的時候根據參數類型個數來判斷調用哪一個函數。

運算符的重載也是重載多態,比如我們定義了一個類Counter,希望這個類內部可以實現'+'的運算,比如Counter ?a,b,c; 初始化后可以有c=a+b;或類似的運算,那么我們需要對‘+’進行重載,給它以運算規則,來保證這句話能通過編譯。

(有5個運算符不可以被重載,分別是: . ?.* ? :: ? sizeof ? ??:)

運算符重載分兩種:作為成員函數重載 ?作為友元函數重載

語法形式為:

? ? ? ? ? ?作為成員函數重載運算符: ? ? ? ? ? ? ? ??? ? ? ? ? ?作為友元函數重載運算符:

函數類型 operator 運算符(形參表){

? ? ? ............;

}

? friend ?函數類型 operator 運算符(形參表){ ? ? ? ? ??

? ? ? ? ?............;

?}

?

?

?

?

?

之前也說過,友元函數其實是定義在函數外的,所以跟函數成員的區別就是友元函數需要兩個形參作為運算符前后的值。

比如我要重載上面的Counter 類型的+ - 運算:?

Counter operator +(Counter c2){

return Counter(this.number+c2.number);

}

//或者友元重載減號:

friend Counter operator -(Counter c1, Counter c2){

return Counter(c1.number-c2.number);

}
//調用時:

Counter a(5),b(3),c,d;
c=a+b;
d=a-b;
//都是可以通過的。

?

/


除了這種加減等常用的外,還有比如-- ++這種前置或后置運算符,比如我們要定義一個counter++; 那么運算符重載為Counter的成員函數,同時函數要帶有一個整數形參(int),它的作用就是區別說明它是后置的++ --。如果是前置,則沒有int形參。如下:

//前置++的重載
Counter Counter::operator ++(){
.........;
}

//后置++的重載

Counter Counter::operator ++(int){
...........;
}

//這樣,當出現++符號時,系統就可以根據位置知道調用哪個函數了:

Counter a(5);
a++; // 相當于調用了 operator ++(0);
++a; // 相當于調用了 operator ++();

強制多態:

就是指講一個變元的類型加以變化,符合一個函數或者操作的具體要求。

比如加法符號,在進行整型和浮點型的運算時,會先強制將整型轉為浮點型,然后再進行運算。

?

包含多態:

包含多態是研究類族中定義于不同類中的同名函數成員的多態行為,主要通過虛函數來實現.

虛函數必須是非靜態成員,經過多次派生之后,族類中可以實現運行過程中的多態。

一般虛函數成員聲明語法:

virtual 函數類型 函數名(形參表){

? ? ? .......................;

}

? 虛函數的聲明只能在類定義中的函數原型聲明時就寫清楚,而不能在寫函數體時才聲明。運行過程中要滿足三個規則:

1. 類之間要滿足類型兼容規則。

2. 聲明時虛函數。

3*. 要由成員函數來調用,或者是通過指針,引用來訪問虛函數。

?理論了解了之后,我們寫個小例子就懂了。

?以下是完整代碼:

虛函數的使用
#include <iostream>
using namespace std;
class Father{
public:
virtual void outputTest(){
cout<<"Father"<<endl;
}

};
class Son1:public Father{
public:
void outputTest(){
cout<<"Son1"<<endl;
}

};
class Son2:public Son1{
public:
void outputTest(){
cout<<"Son2"<<endl;
}

};
// 調用時
int main(){
Father f,*p;
Son1 s1;
Son2 s2;
p=&f;
p->outputTest();
p=&s1;
p->outputTest();
p=&s2;
p->outputTest();
}

?話不多說,我們截圖為證:

? 可見,通過使用virtual這個關鍵詞,我們實現了outputTest這個函數的包含多態。這三個類中,outputTest都是虛函數。

添一句話:如果子類中的一個函數fun,跟父類中的一個虛函數fun,函數名相同,參數表完全一致,返回值也相同,那么這函數就自動被判定為了虛函數。

虛析構函數:它的存在時為了防止某些情況下的空間泄露。所以虛構造函數是不允許存在的。同時,如果一個父類的析構函數是虛函數,那么子類的析構也同樣是虛函數。

下面就說說空間泄露的情況:假如我定義了一個父類Father,里面沒有數據成員,然后我定義了一個子類Son公有繼承父類,并且有一個私有數據成員*int t; Son的構造函數里有 t=new int(0);,析構函數里會delete t;,但是父類自然沒有這一句。這樣我們在定義對象的時候如果有這樣的情況: Father *f=new Son(); ?delete *f; 那么,啊~非常不意外的,可憐的t就被這樣無情的丟在了角落,不使用也不釋放。這樣如果在一個較大成程序里發生的話,很可能會出現內存不足的情況。

解決的辦法,就是在Father的析構函數前面加virtual,具體形式為: virtual ~Father(); 因為很簡單,就再給一次代碼好了,三分鐘搞定:

虛析構函數代碼
#include <iostream>
using namespace std;
class Father{
public:
Father(){};
virtual ~Father(){cout<<"Father delete;"<<endl;};

};
class Son:public Father{
public:
Son(){t=new int(0);};
~Son(){delete t; cout<<"Son delete;"<<endl;};
private:
int *t;

};
// 調用時
int main(){
Father *f=new Son();
delete f;
}

運行結果:

可見,子類的析構函數被調用了,這樣就避免了內存泄露帶來的危害。所以虛析構還是很有用的~!

除了上述兩種虛函數之外,我們還應該知道一種類 叫做:抽象類

抽象類處于類的上一層,它本身無法被實例化,只能通過繼承機制,由抽象類生成非抽象的派生類,再對之實例化

注意:帶有純虛函數的類就是抽象類。但是什么是純虛函數呢?

純虛函數就是在一個基類中聲明的虛函數,它在這個基類里面沒有具體要操作的內容,它存在的意義就是為了讓子類根據自己的需求對這個函數實現不同的接口。

純虛類的定義語法是: virtual 函數返回類型 函數名(參數表)=0; ?其實就是有了一個‘=0’。這樣就不需要給它定義函數體了,所以純虛函數是沒有函數體的。

?

參數多態:

參數多態,就是將程序所處理對象的類型參數化,使得一段程序可以用于處理多種不同類型的對象。

參數的多態,可以通過函數模板類模板實現。

所謂函數模板,我們可以想一個例子:我們通常使用math.h里的很多函數比如絕對值函數abs()的時候,參數可以有int, double等不用類型的參數,那么如果為了每一種類型建立一個重載函數的話,就太麻煩了,因為函數體本身是相同的,所以我們就用一個模板來代替之,如下:

template <typename T>
T abs(T x){
return x<0?-x:x;
}

這樣,我們在調用的時候,如果給的參數是int,那么編譯器就會把typename里的T變為int,這個函數就是個返回int,參數為int的函數了,double等類型也一樣。

函數模板的語法定義:

template <typename T> 或 template <class T> ? ?//表示T是一個類型名或者類名,可以更換為int 、 double、 某個類 等等

返回類型 ?函數名(參數表){? ? ? ?

? ? ? ?.........;

}(注意返回類型不一定為T的~。)

?

?

?

?

?

?

?

類模板:使用類模板可以為類聲明一種模式,是的類中某些數據成員、某些成員函數的參數、某些成員函數的返回值能取任意類型。

類模板的語法定義:?在類的外部定義成員函數的函數體時:

?template <模板參數表>

class 類名{

? ? ? ...........;

}

?template <模板參數表>

返回類型 類名<模板參數表成員>::函數名(參數表){

? ? ? ?........;

}

?

?

?

?

?

?

同樣,我們用一個小例子,一秒搞懂類模板:

#include <iostream>
using namespace std;

template<class Input, class Output>
class Test{
public:
Test(Input in){input=in;}
Output fun();

private:
Input input;
Output output;
};
// 類之外定義函數時的格式:
template<class Input, class Output>
Output Test<Input,Output>::fun(){
return input>0?input:-input;
}



int main(){
Test<int,int> test(-30);
cout<<test.fun()<<endl;
}

查看輸出:

?成功~! 呵呵 雖然沒有含金量,但是該用到的格式這個小程序都用到了,不錯吧~



轉載于:https://www.cnblogs.com/jiaozihardworking/archive/2012/02/18/2356590.html

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

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

相關文章

美育在計算機教育中應用,在現代教育技術中綻放數學美育之花

21世紀是信息化的社會&#xff0c;計算機、網絡等現代技術的飛速發展&#xff0c;作為現代教育技術&#xff0c;計算機多媒體技術和網絡技術已經越來越多地走進小學數學課堂&#xff0c;為深化教學改革&#xff0c;培養學生能力&#xff0c;發展學生個性&#xff0c;提供了嶄新…

.NET Forms身份驗證

.NET表單身份驗證 ASP.NET Forms 身份驗證的簡單實現&#xff1a;1&#xff09;在Web.config文件中配置應用程序使用 Forms 身份驗證&#xff1b;2&#xff09;創建登陸頁面&#xff0c;將用戶身份驗證票證添加到Cookie集合。1.配置文件中設置為Forms驗證<authentication mo…

Oracle SQL篇(三)Oracle ROWNUM 與TOP N分析

首先我們來看一下ROWNUM&#xff1a;含義解釋&#xff1a;1、rownum是oracle為從查詢返回的行的編號&#xff0c;返回的第一行分配的是1&#xff0c;第二行是2&#xff0c;依此類推。這是一個偽列&#xff0c;可以用于限制查詢返回的總行數。2、rownum不能以任何基表的名稱作為…

C++ Primer 第10章 pair類型

//10.2.cpp //至少使用三種方法創建pair對象。 //編寫三個版本的程序&#xff0c;分別采用不同的方法來創建pair對象 //方法1&#xff1a;在定義pair對象時提供初始化式來創建pair對象#include<iostream> #include<vector> #include<utility> #include<st…

計算機對口升學可以報考的學校,對口升學可以報考的學校都在這里,趕快來收藏吧...

對口升學指對口高考&#xff0c;在平常又叫對口單招&#xff0c;對口升學&#xff0c;是從中等職業學校畢業生招生&#xff0c;強調中等職業學校畢業生對口升高職的專業技能考試&#xff0c;以專業技能成績為主要錄取依據的招生辦法。報名條件具有正式學籍的中等職業學校畢業生…

Visual Studio 常用快捷鍵 (二)

想不到上一篇 【Visual Studio 常用快捷鍵】 受這么多人的歡迎。看來大家對Visual Studio的用法非常感興趣。 接下來我準備寫一個 “Visual Studio使用技巧 ” 一個系列的博客。 希望對大家有所幫助 本篇繼續介紹幾個常用的快捷鍵 閱讀目錄 按兩下Tab鍵回退到光標的上一次位置…

js 兼容event.target

function getEventTarget(e){ewindow.event||e;return e.srcElement||e.target; }轉載于:https://www.cnblogs.com/manong13/archive/2012/02/23/2364443.html

企業郵箱收發信息服務器怎么設置,網易閃電郵企業郵箱收發設置教程(IMAP)...

網易閃電郵企業郵箱收發設置教程(IMAP)發表時間 2019-05-30人氣 73(1)啟動閃電郵后&#xff0c;點擊“郵箱---新建郵箱賬戶”菜單&#xff0c;如下圖&#xff1a;(2)輸入“郵箱地址和密碼”&#xff0c;點擊下拉箭頭繼續設置&#xff0c;設置完成后點擊下一步&#xff0c;如下圖…

訂餐系統之Excel批量導入

批量導入現在基本已經成為各類系統的標配了&#xff0c;當前&#xff0c;我們訂餐系統也不例外&#xff0c;什么商家呀、商品呀、優惠碼之類的&#xff0c;都少不了。畢竟嘛&#xff0c;對非開發人員來說&#xff0c;看到Excel肯定比看到很多管理系統還是要親切很多的。這里&am…

需要忽略的一些信號

程序往往會因為收到一些信號導致退出&#xff0c;但很多時候并不是我們想要的&#xff0c;比如往一個已經關閉的socket連接發送數據就會受到SIGPIPE,此信號默認會退出程序&#xff0c;但其實大部分時候我們并不想這么做&#xff0c;所以需要忽略一些信號。常見的有 SIGPIPE SIG…

獲取網頁中選中的文字

獲取頁面中選中的文字 //獲取頁面中選中的文字 function getSelectedText(){if(window.getSelection){ //FFreturn window.getSelection().toString();}else{ //IEreturn document.selection.createRange().text;} }設置或獲取輸入框的選中文字 //設置文字選中 function setSe…

云服務器和獨享虛擬主機的區別,獨享虛擬主機和云服務器的幾大區別

獨享虛擬主機和云服務器的幾大區別發布時間&#xff1a;2020-10-15 19:05:51來源&#xff1a;億速云閱讀&#xff1a;99作者&#xff1a;Leah欄目&#xff1a;云計算今天就跟大家聊聊有關獨享虛擬主機和云服務器的幾大區別&#xff0c;可能很多人都不太了解&#xff0c;為了讓大…

oracle數據庫之數據導入問題

2019獨角獸企業重金招聘Python工程師標準>>> 在oracle數據庫中建立好數據庫以后&#xff0c;需要使用PLSQL進行用戶創建&#xff0c;打開PLSQL&#xff0c;使用時需要使用最高權限進入PLSQL。如下圖&#xff1a; 不需要使用用戶名和密碼&#xff0c;進入數據庫操作。…

轉向ARC的說明

轉自hherima的博客原文&#xff1a;Transitioning to ARC Release Notes&#xff08;蘋果官方文檔&#xff09; ARC是一個編譯器特征&#xff0c;它提供了對OC對象自動管理內存。ARC讓開發者專注于感興趣的代碼和對象的關系&#xff0c;而不用考慮對象的retain和release。 概要…

ubuntu11.10 samba服務器配置

安裝samba可以實現linux下文件和window共享&#xff0c;這樣window下就可以操作linux的文件了。 1、關閉LINUX防火墻 sudo ufw disable 注&#xff1a;ufw是linux下的防火墻操作命令&#xff0c;相關的操作可以查看命令幫助 2、先卸載samba-common sudo ap…

win服務器創建文件夾命令,Win10系統如利用命令提示符或WSL創建任意大小空白文件...

要測試網盤或服務器的上傳&#xff0c;下載速度&#xff0c;需要指定大小的文件用來測試。創建的空白文件雖然沒有任何內容&#xff0c;但是有大小&#xff0c;可以用來測試實際傳輸速度、覆蓋已刪除數據等用途。這篇文章是本站教大家在Win10中用命令或WSL創建任意大小空白文件…

計算UILabel帶行間距的行高

為什么80%的碼農都做不了架構師&#xff1f;>>> //設置lab的行間距 NSMutableAttributedString *attributedString [[NSMutableAttributedString alloc] initWithString:_doubletStr]; NSMutableParagraphStyle *paragraphStyle [[NSMutableParagraphStyle alloc…

FORM級別和數據庫級別的Trace

&#xfeff;&#xfeff;metalink上的文章較全的&#xff0c;中文的可參考我的博客EBS開發技術之trace http://blog.csdn.net/cai_xingyun/article/details/17250971 This document provides instructions on how to create and retrieve Forms and Database level SQL trace…

關于farpoint公司的控件:SPREAD for .NET Windows Forms Ed.的一些簡單方法.

View Code using System;using FarPoint.Win.Spread ;using System.Drawing;using System.Windows.Forms;namespace DFO010{/// <summary>/// Fpspread的相關函數.2006/4/12 制作:Chouka/// </summary> public class Classspd {public Classspd() { }/// <su…

永遠的beyond!(4 days left to get back touch)

永遠的beyond!轉載于:https://www.cnblogs.com/LaoLuo/archive/2012/03/05/2380954.html