青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

健康,快樂,勇敢的寧帥!!

努力、努力、再努力! 沒有什么能阻止我對知識的渴望。

 

C++多態技術---轉載

C++多態技術

《程序員》2004/0 2

摘要

本文介紹了C++中的各種多態性,重點闡述了面向對象的動態多態和基于模板的靜態多態,并初探兩種技術的結合使用。 ?

關鍵詞

函數多態?宏多態 動態多態 靜態多態

導言

多態(polymorphism)一詞最初來源于希臘語 polumorphos,含義是具有多種形式或形態的情形。在程序設計領域,一個廣泛認可的定義是“ 一種將不同的特殊行為和單個泛化記號相關聯的能力”。和 純粹的面向對象程序設計語言不同,C++中的多態有著更廣泛的含義。除了常見的通過 類繼承和虛函數機制生效于運行期的動態多態( dynamic polymorphism )外,模板也允許將不同的特殊行為和單個泛化記號相關聯,由于這種關聯處理于編譯期而非運行期,因此被稱為靜態多態(static polymorphism)。 ?

事實上,帶變量的宏和函數重載機制也允許將不同的特殊行為和單個泛化記號相關聯。然而,習慣上我們并不將它們展現出來的行為稱為多態(或靜態多態)。今天,當我們談及多態時,如果沒有明確所指,默認就是動態多態,而靜態多態則是指基于模板的多態。不過,在這篇以C++各種多態技術為主題的文章中,我們首先還是回顧一下C++社群爭論已久的另一種“多態”:函數多態(function polymorphism),以及更不常提的宏多態(macro polymorphism)。 ?

函數多態

也就是我們常說的函數重載(function overloading)。基于不同的參數列表,同一個函數名字可以指向不同的函數定義: ?

// overload_poly.cpp

#include <iostream>
#include <string>

// 定義兩個重載函數

int my_add(int a, int b)
{
??? return a + b;
}

int my_add(int a, std::string b)
{
??? return a + atoi(b.c_str());
}

int main()
{
??? int i = my_add(1, 2);??????????????? // 兩個整數相加
??? int s = my_add(1, "2");????????????? // 一個整數和一個字符串相加
??? std::cout << "i = " << i << "\n";
??? std::cout << "s = " << s << "\n";
}?

根據參數列表的不同(類型、個數或兼而有之),my_add(1, 2)和my_add(1, "2")被分別編譯為對my_add(int, int)和my_add(int, std::string)的調用。實現原理在于編譯器根據不同的參數列表對同名函數進行名字重整,而后這些同名函數就變成了彼此不同的函數。比方說,也許某個編譯器會將my_add()函數名字分別重整為my_add_int_int()和my_add_int_str()。 ?

宏多態

帶變量的宏可以實現一種初級形式的靜態多態: ?

// macro_poly.cpp

#include <iostream>
#include <string>

// 定義泛化記號:宏ADD
#define ADD(A, B) (A) + (B);

int main()
{
??? int i1(1), i2(2);
??? std::string s1("Hello, "), s2("world!");
??? int i = ADD(i1, i2);??????????????????????? // 兩個整數相加
??? std::string s = ADD(s1, s2);??????????????? // 兩個字符串“相加”
??? std::cout << "i = " << i << "\n";
??? std::cout << "s = " << s << "\n";
}

當程序被編譯時,表達式ADD(i1, i2)和ADD(s1, s2)分別被替換為兩個整數相加和兩個字符串相加的具體表達式。整數相加體現為求和,而字符串相加則體現為連接。程序的輸出結果符合直覺: ?

1 + 2 = 3
Hello, + world! = Hello, world!

動態多態

這就是眾所周知的的多態。現代面向對象語言對這個概念的定義是一致的。其技術基礎在于 繼承機制和虛函數。例如,我們可以定義一個抽象基類Vehicle 和兩個派生于Vehicle的具體類Car和Airplane: ?

// dynamic_poly.h

#include <iostream>

// 公共抽象基類Vehicle
class Vehicle
{
public:
??? virtual void run() const = 0;
};

// 派生于Vehicle的具體類Car
class Car: public Vehicle
{
public:
??? virtual void run() const
??? {
??????? std::cout << "run a car\n";
??? }
};

// 派生于Vehicle的具體類Airplane
class Airplane: public Vehicle
{
public:
??? virtual void run() const
??? {
??????? std::cout << "run a airplane\n";
??? }
};

客戶程序可以通過指向基類Vehicle的指針(或引用)來操縱具體對象。通過指向基類對象的指針(或引用)來調用一個虛函數,會導致對被指向的具體對象之相應成員的調用:

// dynamic_poly_1.cpp

#include <iostream>
#include <vector>
#include "dynamic_poly.h"

// 通過指針run任何vehicle
void run_vehicle(const Vehicle* vehicle)
{
??? vehicle->run();??????????? // 根據vehicle的具體類型調用對應的run()
}

int main()
{
??? Car car;
??? Airplane airplane;
??? run_vehicle(&car);???????? // 調用Car::run()
??? run_vehicle(&airplane);??? // 調用Airplane::run()
}

此例中,關鍵的多態接口元素為 虛函數run()。由于 run_vehicle()的參數為指向基類Vehicle的指針 ,因而無法在編譯期決定使用哪一個版本的run()。在運行期,為了分派函數調用,虛函數被調用的那個對象的完整動態類型將被訪問。這樣一來,對一個Car對象調用 run_vehicle() 實際上將 調用Car::run(),而對于Airplane對象而言將調用Airplane::run()。

或許動態多態最吸引人之處在于處理異質對象集合的能力: ?

// dynamic_poly_2.cpp

#include <iostream>
#include <vector>
#include "dynamic_poly.h"

// run異質vehicles集合
void run_vehicles(const std::vector<Vehicle*>& vehicles)
{
??? for (unsigned int i = 0; i < vehicles.size(); ++i)
??? {
??????? vehicles[i]->run();???? // 根據具體vehicle的類型調用對應的run()
??? }
}

int main()
{
??? Car car;
??? Airplane airplane;
??? std::vector<Vehicle*> v;??? // 異質vehicles集合
??? v.push_back(&car);
??? v.push_back(&airplane);
??? run_vehicles(v);??????????? // run不同類型的vehicles
}

run_vehicles()中,vehicles[i]->run() 依據正被迭代的元素的類型而調用不同的成員函數。這從一個側面體現了面向對象編程風格的優雅。

靜態多態

如果說動態多態是通過虛函數來表達共同接口的話,那么靜態多態則是通過“彼此單獨定義但支持共同操作的具體類”來表達共同性,換句話說,必須存在必需的同名成員函數。 ?

我們可以采用靜態多態機制重寫上一節的例子。這一次,我們不再定義vehicles類層次結構,相反,我們編寫彼此無關的具體類Car和Airplane(它們都有一個run()成員函數): ?

// static_poly.h

#include <iostream>

//具體類Car
class Car
{
public:
??? void run() const
??? {
??????? std::cout << "run a car\n";
??? }
};

//具體類Airplane
class Airplane
{
public:
??? void run() const
??? {
??????? std::cout << "run a airplane\n";
??? }
};

run_vehicle()應用程序被改寫如下:?

// static_poly_1.cpp

#include <iostream>
#include <vector>
#include "static_poly.h"

// 通過引用而run任何vehicle
template <typename Vehicle>
void run_vehicle(const Vehicle& vehicle)
{
??? vehicle.run();??????????? // 根據vehicle的具體類型調用對應的run()
}
?
int main()
{
??? Car car;
??? Airplane airplane;
??? run_vehicle(car);???????? // 調用Car::run()
??? run_vehicle(airplane);??? // 調用Airplane::run()
}?

現在 Vehicle用作 模板參數而非公共基類對象(事實上,這里的 Vehicle只是一個符合直覺的記號而已,此外別無它意 )。經過編譯器處理后,我們最終會得到 run_vehicle <Car>() run_vehicle <Airplane>()兩個不同的函數 這和動態多態不同,動態多態 憑借虛函數分派機制 在運行期只有一個 run_vehicle ()函數。 ?

我們無法再透明地處理異質對象集合了,因為所有類型都必須在編譯期予以決定。不過,為不同的vehicles引入不同的集合只是舉手之勞。由于無需再將集合元素局限于指針或引用,我們現在可以從執行性能和類型安全兩方面獲得好處: ?

// static_poly_2.cpp

#include <iostream>
#include <vector>
#include "static_poly.h"

// run同質vehicles集合
template <typename Vehicle>
void run_vehicles(const std::vector<Vehicle>& vehicles)
{
??? for (unsigned int i = 0; i < vehicles.size(); ++i)?
??? {
??????? vehicles[i].run(); ?????????? // 根據vehicle的具體類型調用相應的run()
??? }
}

int main()
{
??? Car car1, car2;
??? Airplane airplane1, airplane2;

??? std::vector<Car> vc;????????????? // 同質cars集合
??? vc.push_back(car1);
??? vc.push_back(car2);
??? //vc.push_back(airplane1);??????? // 錯誤:類型不匹配
??? run_vehicles(vc);???????????????? // run cars

??? std::vector<Airplane> vs;???????? // 同質airplanes集合
??? vs.push_back(airplane1);
??? vs.push_back(airplane2);
??? //vs.push_back(car1);???????????? // 錯誤:類型不匹配
??? run_vehicles(vs);???????????????? // run airplanes
}

兩種多態機制的結合使用 ?

在一些高級C++應用中,我們可能需要結合使用動態多態和靜態多態兩種機制,以期達到對象操作的優雅、安全和高效。例如,我們既希望一致而優雅地處理vehicles的run問題,又希望“安全而高效”地完成給飛行器(飛機、飛艇等)進行“空中加油”這樣的高難度動作。為此,我們首先將上面的vehicles類層次結構改寫如下: ?

// dscombine_poly.h

#include <iostream>
#include <vector>

// 公共抽象基類Vehicle
class Vehicle
{
??? public:
??? virtual void run() const = 0;
};

// 派生于Vehicle的具體類Car
class Car: public Vehicle
{
public:
??? virtual void run() const
??? {
??????? std::cout << "run a car\n";
??? }
};

// 派生于Vehicle的具體類Airplane
class Airplane: public Vehicle
{
public:
??? virtual void run() const
??? {
??????? std::cout << "run a airplane\n";
??? }
 

??? void add_oil() const
??? {
??????? std::cout << "add oil to airplane\n";
??? }
};

// 派生于Vehicle的具體類Airship
class Airship: public Vehicle
{
public:
??? virtual void run() const
??? {
??????? std::cout << "run a airship\n";
??? }
??

??? void add_oil() const
??? {
??????? std::cout << "add oil to airship\n";
??? }
};

我們理想中的應用程序可以編寫如下: ?

// dscombine_poly.cpp

#include <iostream>
#include <vector>
#include "dscombine_poly.h"

// run異質vehicles集合
void run_vehicles(const std::vector<Vehicle*>& vehicles)
{
??? for (unsigned int i = 0; i < vehicles.size(); ++i)
??? {
??????? vehicles[i]->run();???????????????? // 根據具體的vehicle類型調用對應的run()
??? }
}

// 為某種特定的aircrafts同質對象集合進行“空中加油”
template <typename Aircraft>
void add_oil_to_aircrafts_in_the_sky(const std::vector<Aircraft>& aircrafts)
{
??? for (unsigned int i = 0; i < aircrafts.size(); ++i)
??? {
??????? aircrafts[i].add_oil();
??? }
}

int main()
{
??? Car car1, car2;
??? Airplane airplane1, airplane2;

??? Airship airship1, airship2;
??? std::vector<Vehicle*> v;??????????????? // 異質vehicles集合
??? v.push_back(&car1);
??? v.push_back(&airplane1);
??? v.push_back(&airship1);
??? run_vehicles(v);??????????????????????? // run不同種類的vehicles

??? std::vector<Airplane> vp;?????????????? // 同質airplanes集合
??? vp.push_back(airplane1);
??? vp.push_back(airplane2);
??? add_oil_to_aircrafts_in_the_sky(vp); ?? // 為airplanes進行“空中加油”

??? std::vector<Airship> vs;??????????????? // 同質airships集合
??? vs.push_back(airship1);
??? vs.push_back(airship2);
??? add_oil_to_aircrafts_in_the_sky(vs);??? // 為airships進行“空中加油”
}?

我們保留了類層次結構,目的是為了能 夠利用 run_vehicles()一致而優雅地處理 異質對象集合 vehicles的run問題。同時,利用函數模板add_oil_to_aircrafts_in_the_sky<Aircraft>(),我們仍然可以處理特定種類的vehicles — aircrafts(包括airplanes和airships)的“空中加油”問題。其中,我們避開使用指針,從而在 執行性能和類型安全兩方面達到了預期目標。 ?

結語 ?

長期以來,C++社群對于多態的內涵和外延一直爭論不休。在comp.object這樣的網絡論壇上,此類話題爭論至今仍隨處可見。曾經有人將動態多態稱為inclusion polymorphism,而將靜態多態稱為parametric polymorphism或parameterized polymorphism。 ?

我注意到2003年斯坦福大學公開的一份《C++ and Object-Oriented Programming》教案中明確提到了函數多態概念 — “Function overloading is also referred to as function polymorphism as it involves one function having many forms”。文后的“參考文獻”單元給出了這個網頁鏈接。 ?

可能你是第一次看到宏多態這個術語。不必訝異,也許我就是造出這個術語的“第一人”。顯然,帶變量的宏(或類似于函數的宏或偽函數宏)的替換機制除了免除小型函數的調用開銷之外,也表現出了類似的多態性。在我們上面的例子中,字符串相加所表現出來的符合直覺的連接操作,事實上是由底部運算符重載機制支持的。值得指出的是,C++社群中有人將運算符重載所表現出來的多態稱為ad hoc polymorphism。

David Vandevoorde和Nicolai M. Josuttis在他們的著作《C++ Templates: The Complete Guide》一書中系統地闡述了靜態多態和動態多態技術。因為認為“和其他語言機制關系不大”,這本書沒有提及宏多態(以及函數多態)。(需要說明的是,筆者本人是這本書的繁體中文版譯者之一,本文正是基于這本書的第14章“The Polymorphic Power of Templates”寫作而成)

動態多態只需要一個多態函數,生成的可執行代碼尺寸較小,靜態多態必須針對不同的類型產生不同的模板實體,尺寸會大一些,但生成的代碼會更快,因為無需通過指針進行間接操作。靜態多態比動態多態更加類型安全,因為全部綁定都被檢查于編譯期。正如前面例子所示,你不可將一個錯誤的類型的對象插入到從一個模板實例化而來的容器之中。此外,正如你已經看到的那樣,動態多態可以優雅地處理異質對象集合,而靜態多態可以用來實現安全、高效的同質對象集合操作。 ?

靜態多態為C++帶來了泛型編程(generic programming)的概念。泛型編程可以認為是“組件功能基于框架整體而設計”的模板編程。STL就是泛型編程的一個典范。STL是一個框架,它提供了大量的算法、容器和迭代器,全部以模板技術實現。從理論上講,STL的功能當然可以使用動態多態來實現,不過這樣一來其性能必將大打折扣。 ?

靜態多態還為C++社群帶來了泛型模式(generic patterns)的概念。理論上,每一個需要通過虛函數和類繼承而支持的設計模式都可以利用基于模板的靜態多態技術(甚至可以結合使用動態多態和靜態多態兩種技術)而實現。正如你看到的那樣,Andrei Alexandrescu的天才作品《Modern C++ Design: Generic Programming and Design Patterns Applied》(Addison-Wesley)和Loki程序庫 已經走在了我們的前面。

參考文獻

1. David Vandevoorde, Nicolai M. Josuttis, C++ Templates: The Complete Guide, Addison Wesley, 2002.

2. Chris Neumann, CS193d (Summer 2003) C++ and Object-Oriented Programming, http://www.stanford.edu/class/cs193d/, 2003.

榮耀
200 3 10
南京師范大學
www.royaloo.com

posted on 2006-11-25 20:36 ningfangli 閱讀(201) 評論(0)  編輯 收藏 引用 所屬分類: C++技術

導航

統計

公告

Dict.CN 在線詞典, 英語學習, 在線翻譯

常用鏈接

留言簿(4)

隨筆檔案

文章分類

文章檔案

搜索

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲高清网站| 国产视频亚洲| 午夜精品偷拍| 亚洲专区在线| 性伦欧美刺激片在线观看| 亚洲一区二区三区精品视频| 一区二区欧美亚洲| 亚洲在线观看视频网站| 亚洲女优在线| 久久久一本精品99久久精品66| 久久激情综合| 欧美激情免费观看| 一区二区三区精品久久久| 亚洲欧美日韩在线高清直播| 亚洲一区免费观看| 久久国产视频网站| 欧美成人亚洲成人| 国产欧美一级| 亚洲精品视频在线观看免费| 亚洲欧美精品suv| 久热精品视频在线免费观看 | 一本久久综合| 亚洲欧美日本另类| 欧美成人第一页| 国产精品99久久不卡二区| 日韩亚洲视频在线| 欧美成人一区二区三区| 亚洲国产精品成人综合| 一区二区三区高清视频在线观看| 性久久久久久久久| 欧美日韩蜜桃| 亚洲大胆在线| 午夜久久资源| 亚洲第一狼人社区| 性伦欧美刺激片在线观看| 99在线热播精品免费99热| 久久久青草青青国产亚洲免观| 欧美国产激情| 伊人久久婷婷| 久久精品国产99国产精品| 久久精品视频在线| 亚洲一区二区免费看| 欧美www视频| 国内精品视频在线观看| 亚洲夜间福利| 久久久久www| 亚洲欧美在线一区| 欧美日韩直播| 在线性视频日韩欧美| 欧美国产日韩二区| 久久资源av| 在线播放视频一区| 久久精品青青大伊人av| 中文在线资源观看网站视频免费不卡| 欧美激情久久久久| 亚洲精品免费观看| 亚洲国产精品一区制服丝袜| 久久久精品性| 在线观看精品视频| 麻豆精品国产91久久久久久| 欧美在线在线| 激情自拍一区| 免费看av成人| 久久久欧美精品| 影音先锋成人资源站| 老牛影视一区二区三区| 久久久777| 亚洲二区三区四区| 亚洲国产精品综合| 欧美精品电影| 亚洲午夜电影网| 一区二区三区国产在线| 国产精品日韩久久久| 欧美专区在线| 欧美中文字幕在线| 经典三级久久| 欧美激情 亚洲a∨综合| 欧美精品一区二区三区很污很色的| 亚洲开发第一视频在线播放| 日韩午夜精品| 国产亚洲精品一区二555| 欧美阿v一级看视频| 欧美日本国产视频| 亚洲欧美日韩电影| 亚洲国产精品一区二区第一页 | 嫩草国产精品入口| 亚洲视屏一区| 久久精品色图| 亚洲经典在线| 亚洲一区区二区| 在线看视频不卡| 一区二区三区高清| 海角社区69精品视频| 亚洲精品一区二区三区四区高清| 国产精品国产精品| 欧美国产精品专区| 国产精品午夜电影| 亚洲第一二三四五区| 国产日产欧美精品| 日韩网站免费观看| 亚洲欧洲午夜| 久久国产天堂福利天堂| 亚洲一区二区视频| 欧美激情视频在线播放| 久久久免费精品| 国产精品久久一级| 亚洲欧洲精品成人久久奇米网| 国产精品视频一区二区高潮| 亚洲激情小视频| 在线精品亚洲一区二区| 亚洲欧美日韩高清| 亚洲一区二区成人在线观看| 免费观看成人www动漫视频| 亚洲欧美日韩专区| 欧美国产一区视频在线观看| 国产精品美腿一区在线看| 欧美激情bt| 国内成人在线| 在线一区二区三区做爰视频网站 | 欧美成人一区二区三区| 久久躁狠狠躁夜夜爽| 欧美日韩亚洲一区二区| 亚洲黄页视频免费观看| 国产视频精品免费播放| 亚洲欧美日韩精品综合在线观看 | 久久久www| 欧美性大战久久久久久久| 亚洲精品综合精品自拍| 在线播放不卡| 久久综合激情| 一本色道久久综合亚洲91| 欧美成人激情视频| 亚洲国产高清视频| 国内激情久久| 久久一区免费| 久热re这里精品视频在线6| 精品福利av| 欧美一区二区三区播放老司机| 一区二区三区四区五区视频| 老司机精品福利视频| 欧美日本在线观看| 亚洲国产cao| 国产精品午夜在线| 亚洲国产精品第一区二区| 亚洲第一综合天堂另类专| 亚洲尤物视频在线| 久久久www成人免费精品| 国产精品午夜视频| 久久久噜噜噜久久中文字免| 亚洲无限av看| 国产精品久久久久一区二区三区| 亚洲欧美激情视频| 亚洲欧美一区二区三区久久 | 欧美专区在线| 久久狠狠一本精品综合网| 在线观看日韩精品| 久久一区视频| 亚洲成色www8888| 亚洲精品乱码久久久久久蜜桃麻豆| 久久亚洲精品一区二区| 亚洲精品一区二区三区在线观看| 亚洲黄网站在线观看| 国产精品高潮粉嫩av| 欧美激情第三页| 亚洲影院污污.| 国内精品久久久久久久影视麻豆 | 亚洲二区免费| 亚洲一区二区视频在线| 国产精品亚洲综合色区韩国| 欧美在线地址| 美女被久久久| 亚洲一区二区三区免费视频| 国产精品大片wwwwww| 老司机成人网| 亚洲国产精品久久久久秋霞不卡 | 欧美1区2区3区| 亚洲精品在线视频| 欧美视频日韩| 91久久久亚洲精品| 亚洲在线视频一区| 亚洲茄子视频| 国产精品国产福利国产秒拍| 欧美成人伊人久久综合网| 欧美国产视频日韩| 国产一区二区三区免费在线观看| 亚洲综合精品自拍| 亚洲欧洲免费视频| 国产一区二区三区视频在线观看 | 久久国产精品72免费观看| 亚洲精品一区二区三| 欧美一级大片在线观看| 在线视频欧美日韩| 一区二区三区在线观看国产| 国产精品综合不卡av| 免费成人你懂的| 午夜精品亚洲| 亚洲伊人伊色伊影伊综合网| 欧美sm重口味系列视频在线观看| 久久se精品一区二区| 亚洲美女一区|