深入理解C++的動態綁定和靜態綁定

為了支持c++的多態性,才用了動態綁定和靜態綁定。理解他們的區別有助于更好的理解多態性,以及在編程的過程中避免犯錯誤。
需要理解四個名詞:
1、對象的靜態類型:對象在聲明時采用的類型。是在編譯期確定的。
2、對象的動態類型:目前所指對象的類型。是在運行期決定的。對象的動態類型可以更改,但是靜態類型無法更改。
關于對象的靜態類型和動態類型,看一個示例:

view plaincopy to clipboardprint?
class B??
{??
}??
class C : public B??
{??
}??
class D : public B??
{??
}??
D* pD = new D();//pD的靜態類型是它聲明的類型D*,動態類型也是D*??
B* pB = pD;//pB的靜態類型是它聲明的類型B*,動態類型是pB所指向的對象pD的類型D*??
C* pC = new C();??
pB = pC;//pB的動態類型是可以更改的,現在它的動態類型是C*?
class B
{
}
class C : public B
{
}
class D : public B
{
}
D* pD = new D();//pD的靜態類型是它聲明的類型D*,動態類型也是D*
B* pB = pD;//pB的靜態類型是它聲明的類型B*,動態類型是pB所指向的對象pD的類型D*
C* pC = new C();
pB = pC;//pB的動態類型是可以更改的,現在它的動態類型是C*
?

3、靜態綁定:綁定的是對象的靜態類型,某特性(比如函數)依賴于對象的靜態類型,發生在編譯期。
4、動態綁定:綁定的是對象的動態類型,某特性(比如函數)依賴于對象的動態類型,發生在運行期。
view plaincopy to clipboardprint?
class B??
{??
??? void DoSomething();??
??? virtual void vfun();??
}??
class C : public B??
{??
??? void DoSomething();//首先說明一下,這個子類重新定義了父類的no-virtual函數,這是一個不好的設計,會導致名稱遮掩;這里只是為了說明動態綁定和靜態綁定才這樣使用。??
??? virtual void vfun();??
}??
class D : public B??
{??
??? void DoSomething();??
??? virtual void vfun();??
}??
D* pD = new D();??
B* pB = pD;?
class B
{
??? void DoSomething();
??? virtual void vfun();
}
class C : public B
{
??? void DoSomething();//首先說明一下,這個子類重新定義了父類的no-virtual函數,這是一個不好的設計,會導致名稱遮掩;這里只是為了說明動態綁定和靜態綁定才這樣使用。
??? virtual void vfun();
}
class D : public B
{
??? void DoSomething();
??? virtual void vfun();
}
D* pD = new D();
B* pB = pD;

讓我們看一下,pD->DoSomething()和pB->DoSomething()調用的是同一個函數嗎?
不是的,雖然pD和pB都指向同一個對象。因為函數DoSomething是一個no-virtual函數,它是靜態綁定的,也就是編譯器會在編譯期根據對象的靜態類型來選擇函數。pD的靜態類型是D*,那么編譯器在處理pD->DoSomething()的時候會將它指向D::DoSomething()。同理,pB的靜態類型是B*,那pB->DoSomething()調用的就是B::DoSomething()。

讓我們再來看一下,pD->vfun()和pB->vfun()調用的是同一個函數嗎?
是的。因為vfun是一個虛函數,它動態綁定的,也就是說它綁定的是對象的動態類型,pB和pD雖然靜態類型不同,但是他們同時指向一個對象,他們的動態類型是相同的,都是D*,所以,他們的調用的是同一個函數:D::vfun()。

上面都是針對對象指針的情況,對于引用(reference)的情況同樣適用。

指針和引用的動態類型和靜態類型可能會不一致,但是對象的動態類型和靜態類型是一致的。
D D;
D.DoSomething()和D.vfun()永遠調用的都是D::DoSomething()和D::vfun()。

至于那些事動態綁定,那些事靜態綁定,有篇文章總結的非常好:
我總結了一句話:只有虛函數才使用的是動態綁定,其他的全部是靜態綁定。目前我還沒有發現不適用這句話的,如果有錯誤,希望你可以指出來。

特別需要注意的地方
當缺省參數和虛函數一起出現的時候情況有點復雜,極易出錯。我們知道,虛函數是動態綁定的,但是為了執行效率,缺省參數是靜態綁定的。
view plaincopy to clipboardprint?
class B??
{??
?virtual void vfun(int i = 10);??
}??
class D : public B??
{??
?virtual void vfun(int i = 20);??
}??
D* pD = new D();??
B* pB = pD;??
pD->vfun();??
pB->vfun();?
class B
{
?virtual void vfun(int i = 10);
}
class D : public B
{
?virtual void vfun(int i = 20);
}
D* pD = new D();
B* pB = pD;
pD->vfun();
pB->vfun();
?
有上面的分析可知pD->vfun()和pB->vfun()調用都是函數D::vfun(),但是他們的缺省參數是多少?
分析一下,缺省參數是靜態綁定的,pD->vfun()時,pD的靜態類型是D*,所以它的缺省參數應該是20;同理,pB->vfun()的缺省參數應該是10。編寫代碼驗證了一下,正確。
對于這個特性,估計沒有人會喜歡。所以,永遠記住:
“絕不重新定義繼承而來的缺省參數(Never redefine function’s inherited default parameters value.)”

關于c++語言
目前我基本上都是在c++的子集“面向對象編程”下工作,對于更復雜的知識了解的還不是很多。即便如此,到目前為止編程時需要注意的東西已經很多,而且后面可能還會繼續增多,這也許是很多人反對c++的原因。
c++是Google的四大官方語言之一。但是Google近幾年確推出了go語言,而且定位是和c/c++相似。考慮這種情況,我認為可能是Google的程序員們深感c++的復雜,所以想開發一種c++的替代語言。有時間要了解一下go語言,看它在類似c++的問題上時如何取舍的。

?

本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/chgaowei/archive/2011/05/17/6427731.aspx

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

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

相關文章

增量值編碼器、單圈絕對值編碼器、多圈絕對值編碼器

主流的伺服電機位置反饋元件包括增量值編碼器,單圈絕對值編碼器,多圈絕對值編碼器,旋轉變壓器等。下面分別介紹: 增量值編碼器增量式編碼器是將位移轉換成周期性的電信號,再把這個電信號轉變成計數脈沖,用…

HALCON示例程序inspect_bottle_mouth.hdev玻璃瓶口缺陷檢測

HALCON示例程序inspect_bottle_mouth.hdev玻璃瓶口缺陷檢測 示例程序源碼(加注釋) 定義變量并初始化 SmoothX : 501 ThresholdOffset : 25 MinDefectSize : 50 PolarResolution : 640 RingSize : 70 get_system (‘store_empty_region’, StoreEmptyReg…

靜態主席樹總結(靜態區間的k大)

靜態主席樹總結(靜態區間的k大) 首先我們先來看一道題 給定N個正整數構成的序列,將對于指定的閉區間查詢其區間內的第K小值。 輸入格式: 第一行包含兩個正整數N、M,分別表示序列的長度和查詢的個數。 第二行包含N個正整數&a…

Java中MySQL事務處理舉例

實例(以sql語句中的insert語句為例) import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement;/*** 事務的基本用法**/ …

永磁交流伺服電機的工作原理與更換新編碼器后的常規零位校正方法

http://wuhuotun.blog.163.com/blog/static/73085450200910655748516/ 永磁交流伺服電機的編碼器相位為何要與轉子磁極相位對齊 其唯一目的就是要達成矢量控制的目標,使d軸勵磁分量和q軸出力分量解耦,令永磁交流伺服電機定子繞組產生的電磁場始終正交于…

理解Java中字符流與字節流的區別

1. 什么是流 Java中的流是對字節序列的抽象,我們可以想象有一個水管,只不過現在流動在水管中的不再是水,而是字節序列。和水流一樣,Java中的流也具有一個“流動的方向”,通常可以從中讀入一個字節序列的對象被稱為輸入…

HALCON示例程序inspect_solar_fingers.hdev太陽能電池板電路缺陷檢測

HALCON示例程序inspect_solar_fingers.hdev太陽能電池板電路缺陷檢測 示例程序源碼(加注釋) 關于顯示類函數解釋 dev_update_off () dev_close_window () ImageName : ‘solar_cell/solar_cell_’ read_image (Image, ImageName ‘01’) dev_open_win…

C++多線程 例子

C多線程 例子2008-08-21 15:11//這是2個線程模擬賣火車票的小程序#include <windows.h>#include <iostream.h>DWORD WINAPI Fun1Proc(LPVOID lpParameter);//thread dataDWORD WINAPI Fun2Proc(LPVOID lpParameter);//thread dataintindex0;inttickets10;HANDLE hM…

2018/03/25

2019獨角獸企業重金招聘Python工程師標準>>> March 25 2018 Sunday Weather&#xff1a;cloudy 1、需求&#xff1a; a0.5 b3 ca*b 求c的值&#xff1a; [rootDasoncheng sbin]# cat a.sh #!/bin/bash a0.5 b3 cecho $a*$b |bc echo $canswer referred&#xff1a;…

統計字符串中每種字符類型的個數demo

/** 統計字符串中每中字符類型的個數&#xff0c;思路&#xff1a;* 1、鍵盤錄入一個字符串* 2、獲取到每個字符&#xff0c;遍歷字符串* for (int i 0; i < s.length(); i) {char ch s.charAt(i);* 3、判斷每個字符屬于哪種類型&#xff0c;對應的個數*/package cn.strin…

css3 圖片放大縮小閃爍效果

直接把圖片替換就可以了&#xff0c;我的圖片是透明的&#xff0c;所以body設置為黑色的&#xff0c;不不要可以去掉 <!doctype html><html lang"en"><head> <meta charset"UTF-8"> <title>css3 圖片放大縮小閃爍效果</t…

HALCON示例程序max_connection.hdev確定分割區域的最大區域數目

HALCON示例程序max_connection.hdev確定分割區域的最大區域數目 示例程序源碼&#xff08;加注釋&#xff09; read_image (Image, ‘monkey’) get_system (‘max_connection’, Information) set_system (‘max_connection’, 0) threshold (Image, Region, 128, 255) 區域…

elasticsearch分詞聚合查詢demo

2019獨角獸企業重金招聘Python工程師標準>>> 我們在通過elasticsearch查詢text類型的字段時&#xff0c;我們使用aggs進行聚合某個text類型field。這時elasticsearch會自動進行分詞將分詞后的結果進行聚合。獲取每一個分詞出現在文檔的文檔個數。注意&#xff1a;是…

軟件工程進度條-第十五周

第十五周 所花時間&#xff08;包括上課&#xff09; 23 代碼量&#xff08;行&#xff09; 1200 博客量&#xff08;篇&#xff09; 6 了解到的知識點 1、了解ListView的基本用法&#xff0c;并改變焦點觸碰事件&#xff1b; 2、理解團隊開發后進行軟件項目總結的益處…

Spring實戰第七章

一、SpringMVC配置代替方案 1自定DispatcherServlet 按照AbstractAnnotationConfigDispatcherServletInitializer的定義&#xff0c;它會創建DispatcherServlet和ContextLoaderListener。 AbstractAnnotationConfigDispatcherServletInitializer有三個方法是必須要重載的abstra…

EPSON TCP/IP 通信

EPSON SCARA機器人TCP/IP 通信時&#xff0c;涉及到的相關指令說明。 14.3 TCP/IP命令。 OpenNet //打開TCP/IP端口。 ChkNet //返回端口狀態&#xff1a;等待讀取的字節數或錯誤條件。 CloseNet //關閉TCP/IP端口。 SetNet //運行時或從命令窗口中設置通信端…

JDBC(九)DatabaseMetaData 數據庫元數據

通過java.sql.DatabaseMetaData 接口&#xff0c;我們能獲取到數據庫的列表、列等信息。 DatabaseMetaData 接口包含了許多方法&#xff0c;這里值介紹常用的。 ###獲取 DatabaseMetaData 實例對象 DatabaseMetaData databaseMetaData connection.getMetaData(); 復制代碼###獲…

C++多線程(一)

C多線程&#xff08;一&#xff09; WIN 多線程API一 簡單實例比較簡單的代碼&#xff0c;創建10個線程&#xff0c;其中使第4個線程在一創建就掛起&#xff0c;等到其他的線程執行的差不多的時候再使第4個線程恢復執行。#include <stdio.h>#include <stdlib.h>#i…

HALCON示例程序measure_ball_bond.hdev電路板焊點位置測量

HALCON示例程序measure_ball_bond.hdev電路板焊點位置測量 示例程序源碼&#xff08;加注釋&#xff09; 關于顯示類函數解釋 dev_update_off () dev_close_window () FileName : ‘bonds/ball_bond_ccd_’ read_image (Image, FileName 1$‘02’) dev_open_window_fit_imag…

rank()over 函數的使用

1. over()是分析函數&#xff0c;可以和rank()函數配合使用&#xff0c;也可以和其他函數配合使用。取每個學科排名前三的分數&#xff0c;sql語句如下&#xff1a; select * from (select rank() over(partition by subject order by mark desc) rk,S.* from S) T where T.rk&…