c++動態聯編與靜態聯編
【關鍵詞】:靜態聯編;動態聯編;虛擬函式
在C++中,聯編是指一個計算機程式的不同部分彼此關聯的過程。按照聯編所進行的階段不同,可分為兩種不同的聯編方法:靜態聯編和動態聯編。
1. 靜態聯編
靜態聯編是指聯編工作在編譯階段完成的,這種聯編過程是在程式執行之前完成的,又稱為早期聯編。要實現靜態聯編,在編譯階段就必須確定程式中的操作呼叫(如函式呼叫)與執行該操作程式碼間的關係,確定這種關係稱為束定,在編譯時的束定稱為靜態束定。靜態聯編對函式的選擇是基於指向物件的指標或者引用的型別。其優點是效率高,但靈活性差。
例1:靜態聯編
#include"iostream.h"
class A
{public:
voidf(){cout<<"A"<<"";}
};
classB:publicA
{public:
voidf(){cout<<"B"<<endl;}
};
Void main()
{A*pa=NULL;
Aa;Bb;
pa=&a;pa->f();
pa=&b;pa->f();
}
該程式的執行結果為:A A
從例1程式的執行結果可以看出,通過物件指標進行的普通成員函式的呼叫,僅僅與指標的型別有關,而與此刻指標正指向什麼物件無關。要想實現當指標指向不同物件時執行不同的操作,就必須將基類中相應的成員函式定義為虛擬函式,進行動態聯編。
2. 動態聯編
動態聯編是指聯編在程式執行時動態地進行,根據當時的情況來確定呼叫哪個同名函式,實際上是在執行時虛擬函式的實現。這種聯編又稱為晚期聯編,或動態束定。動態聯編對成員函式的選擇是基於物件的型別,針對不同的物件型別將做出不同的編譯結果。C++中一般情況下的聯編是靜態聯編,但是當涉及到多型性和虛擬函式時應該使用動態聯編。動態聯編的優點是靈活性強,但效率低。
動態聯編規定,只能通過指向基類的指標或基類物件的引用來呼叫虛擬函式,其格式為:指向基類的指標變數名->虛擬函式名(實參表)或基類物件的引用名.虛擬函式名(實參表)
實現動態聯編需要同時滿足以下三個條件:
①必須把動態聯編的行為定義為類的虛擬函式。
②類之間應滿足子型別關係,通常表現為一個類從另一個類公有派生而來。
③必須先使用基類指標指向子型別的物件,然後直接或者間接使用基類指標呼叫虛擬函式。
例2:動態聯編
#include"iostream.h"
classA
{public:
Virtual voidf()//虛擬函式
{cout<<"A"<<"";}};
classB:publicA
{public:
Virtual voidf()//虛擬函式
{cout<<"B"<<endl;}
};
voidmain()
{ A*pa=NULL;
Aa;Bb;
pa=&a;
pa->f();
pa=&b;
pa->f();
}
該程式的執行結果為:A B
從例2程式的執行結果可以看出,將基類A中的函式f定義為虛擬函式後,當指標指向不同物件時執行了不同的操作,實現了動態聯編。
3. 動態聯編分析
動態聯編要求派生類中的虛擬函式與基類中對應的虛擬函式具有相同的名稱、相同的引數個數和相同的對應引數型別、返回值或者相同,或者都返回指標或引用,並且派生類虛擬函式所返回的指標或引用的基型別是基類中虛擬函式所返回的指標或引用的基型別的子型別。如果不滿足這些條件,派生類中的虛擬函式將丟失其虛特性,在呼叫時進行靜態聯編。
例3:通過指向基類的指標來呼叫虛擬函式
#include"iostream.h"
Class base
{
public:
virtual void fun1(){cout<<"base fun1"<<endl;}
virtual void fun2(){cout<<"base fun2"<<endl;}
void fun3(){cout<<"base fun3"<<endl;}
void fun4(){cout<<"base fun4"<<endl;}
};
Class derived:public base
{public:
Virtual void fun1(){cout<<"derived fun1"<<endl;}
Virtual void fun2(intx){cout<<"derived fun2"<<endl;}
Virtual void fun3(){cout<<"derived fun3"<<endl;}
Void fun4(){cout<<"derived fun4"<<endl;}};
Void main()
{base*pb;
derivedd;
pb=&d;//通過指向基類的指標來呼叫虛擬函式pb->fun1();pb->fun2();pb->fun3();pb->fun4();}
該程式的執行結果:
Derived fun1 base fun2 base fun3 base fun4
本例中函式fun1在基類base和派生類derived中均使用了關鍵字virtual定義為虛擬函式,並且這兩個虛擬函式具有相同的引數個數、引數型別和返回值型別。因此,當指標pb訪問fun1函式時,採用的是動態聯編。函式fun2在基類base和派生類de-rived中定義為虛擬函式,但這兩個虛擬函式具有不同的引數個數。函式fun2丟失了其虛特性,在呼叫時進行靜態聯編。函式fun3在基類base中說明為一般函式,在派生類derived中定義為虛擬函式。在這種情況下,應該以基類中說明的成員函式的特性為標準,即函式fun3是一般成員函式,在呼叫時採用靜態聯編。函式fun4在基類base和派生類derived中均說明為一般函式,因此基類指標pb只能訪問base中的成員。
例4:通過基類物件的引用來呼叫虛擬函式
#include"iostream.h"
Class CPoint
{public:
CPoint(doublei,doublej){x=i;y=j;}
Virtual double Area(){return 0.0;}
private:
doublex,y;
};
Class CRectangle:public CPoint
{public:
CRectangle(double i,double j,double k,double l);
Double Area(){return w*h;}
private:
double w,h;
};
CRectangle::CRectangle(double i,double j,double k,double l):CPoint(i,j)
{ w=k;h=l; }
Void fun(CPoint &s)
{ cout<<s.Area()<<endl; }//通過基類物件的引用來呼叫虛擬函式
Void main()
{
CRectangle rec(3.0,5.2,15.0,25.0);
fun(rec);
}
該程式的執行結果為:375
例4中的成員函式Area在基類CPoint中使用了關鍵字virtual定義為虛擬函式,在派生類CRectangle中定義為一般函式,但是進行了動態聯編,結果為15*25即375。這是因為一個虛擬函式無論被公有繼承多少次,它仍然保持其虛特性。在派生類中重新定義虛擬函式時,關鍵字virtual可以寫也可不寫,但為了保持良好的程式設計風格,避免引起混亂時,應寫上該關鍵字。
4. 小結
從以上四個例子中可以看出:虛擬函式是實現多型的基礎,是實現動態聯編的必要條件之一。動態聯編要靠虛擬函式來實現,虛擬函式要靠動態聯編的支援。兩者相輔相成,缺一不可。相關推薦
c++動態聯編與靜態聯編
摘要】:本文闡述了靜態聯編和動態聯編的概念和區別,通過具體例項分析了實現動態聯編的條件,指出了虛擬函式是實現動態聯編的基礎。 【關鍵詞】:靜態聯編;動態聯編;虛擬函式 在C++中,聯編是指一個計算機程式的不同部分彼此
動態聯編與靜態聯編
首先,聯編是指一個計算機程式的不同部分彼此關聯的過程。 靜態聯編是指聯編工作在編譯階段完成的,這種聯編過程是在程式執行之前完成的,又稱為早期聯編。要實現靜態聯編,在編譯階段就必須確定程式中的操作呼叫
C++中的虛擬函式與靜態聯編和動態聯編
程式在呼叫函式時,將使用哪個可執行程式碼塊呢?編譯器負責回答這個問題,將原始碼中的函式呼叫解釋為執行特定的函式程式碼塊被稱為函式名聯編。在C中,因為每個函式名都對應一個不同的函式,而在C++中,由於函式過載的緣故,編譯器必須檢視函式引數以及函式名才能確定
c++動態聯編和靜態聯編
將一個呼叫函式者聯結上正確的被呼叫函式,這過程叫做函式聯編。c++中的聯編分兩種,分為靜態聯編和動態聯編。 為加virtual時是靜態聯編;加入virtual是動態聯編。只有在使用指標或者引用時,才能實現在執行時的動態聯編。 #include<io
多型的實現方式以及動態聯編、靜態聯編
多型,顧名思義“ 多種狀態”,在面嚮物件語言中,介面的多種不同實現方式即為多型。 也就是允許將子類型別的指標賦值給父類型別的指標。 classA{public:A();virtualvoidk(){qDebug()<<"aaaaaaaaa";}}; clas
C語言函式庫:動態連結庫與靜態連結庫
首先,函式庫就是一些事先寫好的函式的集合,是別人分享的,我們可以拿來使用的。經過一些校準和整理,就形成一份標準化的函式庫。例如glibc 函式庫有兩種提供形式:動態連結庫與靜態連結庫 早起函式庫裡的函式都是直接共享的,就是所謂的開源社群。後來函式庫商業化,就出現了靜態連結庫與動態連結庫。
c++動態內存與智能指針
under 動態對象 存儲 顯式 運算符 智能 成員 對象類型 自動 目前為止我們學過靜態內存和棧內存,分配在其中的對象由編譯器自動創建和銷毀, 靜態內存:用來保存局部static對象、類的static數據成員、以及定義在任何函數體之外的變量。在對象使用之前分配,程序結束時
編譯原理——動態語義錯誤與靜態語義錯誤
產生 是個 font 編譯原理 編譯器 原理 sin 直接 語義 動態語義錯誤: 邏輯上的錯誤,比如死循環等,編譯器在編譯的時候並未發現,但邏輯上這是個錯誤; 靜態語義錯誤: 可被編譯器發現的語法錯誤,比如 (5+6(); 這種在編譯器編譯的時候就會被發現的語
2.Java陣列_一維陣列二維陣列的動態初始化與靜態初始化、方法接收/返回/修改陣列、java對陣列的排序/全拷貝/部分拷貝
Java陣列----引用資料型別,必須在使用前先初始化;否則會nullPointerException(執行時異常)。 (引用傳遞:多個棧記憶體指向同一塊堆記憶體) 1.一維陣列初始化 (1)動態初始化(宣告並開闢陣列) 資料型別[] 陣列名稱 = new 資料型別[長度]; 如
深入理解Java動態繫結與靜態繫結
動態繫結 以下是我的理解,可能和其他大佬們的理解略有偏差,如有想法不同的或者有錯誤的地方歡迎您指出來,謝謝 先上程式碼: public class Father { public void f() { System.out.println("Father meth
動態連結庫與靜態連結庫的優缺點
轉載參考博文 1、靜態連結庫的優點: (1) 程式碼裝載速度快,執行速度略比動態連結庫快; (2) 只需保證在開發者的計算機中有正確的.LIB檔案,在以二進位制形式釋出程式時不需考慮在使用者的計算機上.LIB檔案是否存在及版本問題,可避免dll地獄等問題。 2 、動態連結庫的優點 (
Go 生成C動態庫.so和靜態庫.a
Go 生成C動態庫.so和靜態庫.a 原始碼 package main import "C" import "fmt" //export hello func hello(){ fmt.Println("hello world") } //export add func
C++ 動態繫結和靜態繫結
virtual 函式實現多型性 #include <iostream> using namespace std; struct TreeNode { TreeNode *left; TreeNode *rignt; }; class Gener
hiberbate一對多的級聯新增和級聯查詢與級聯刪除
1. 什麼是關聯(association) 1.1 關聯指的是類之間的引用關係。如果類A與類B關聯,那麼被引用的類B將被定義為類A的屬性。例如: public class A{ private B b = new B; public A(){} } 1.2 關聯
【C++】友元與靜態成員
友元 C++中,類外的成員不能訪問類內的私有和保護型別成員。而友元函式可以不受訪問限制訪問類的任何成員。友元函式雖然可以在類內進行宣告,但是友元函式不是成員函式,因此沒有this指標。 舉例說明: class Clock { public: Clo
hibernate一對多、多對多級聯儲存與級聯刪除與修改外來鍵
1、一對多複雜寫法級聯儲存 //建立一個公司物件,為公司物件新增員工 GongsiEntity gongsi=new GongsiEntity(); gongsi.setGname("百度"); YuangongEntity
Windows動態連結庫與靜態庫
一、靜態庫(lib) ①Win32程式不能連結64位靜態庫; ②Debug下可以連結Release版的靜態庫,反之亦然; 二、動態連結庫(dll) ①32位程式依賴32位dll,dll檔案可以放在“C:\Windows”目錄下,也可以放在“C:\Windows\SysWOW64”目錄,但不能
c++動態庫生成與呼叫
一、生成動態庫(含標頭檔案、不含標頭檔案) 以生成dllTest.dll為例(工程名為dllTest、 標頭檔案名為dllTest.h、 原始檔名為dllTest.cpp) 1.1 不含標頭檔案的動態庫 我們生成的動態庫想要被別人呼叫,那麼一定要將想要被呼叫的函式匯出,使用
[C++]動態繫結和靜態繫結
C++的動態繫結和靜態繫結 物件的靜態型別: 物件在宣告時採用的型別。是在編譯期確定的。 物件的動態型別: 目前所指物件的型別。是在執行期決定的。物件的動態型別可以更改,但是靜態型別無法更改。
Java動態繫結與靜態繫結
Java動態繫結來自於繼承體現,子類繼承父類,子類重新覆蓋了父類的方法,就是動態繫結,以下舉例: (動態繫結是在執行期間) 動物類: /** * 建立一個動物類 * @author Liudeli */ public class Animal {