• <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>

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

            努力、努力、再努力! 沒有什么能阻止我對(duì)知識(shí)的渴望。

             

            C++多態(tài)技術(shù)---轉(zhuǎn)載

            C++多態(tài)技術(shù)

            《程序員》2004/0 2

            摘要

            本文介紹了C++中的各種多態(tài)性,重點(diǎn)闡述了面向?qū)ο蟮膭?dòng)態(tài)多態(tài)和基于模板的靜態(tài)多態(tài),并初探兩種技術(shù)的結(jié)合使用。 ?

            關(guān)鍵詞

            函數(shù)多態(tài)?宏多態(tài) 動(dòng)態(tài)多態(tài) 靜態(tài)多態(tài)

            導(dǎo)言

            多態(tài)(polymorphism)一詞最初來源于希臘語(yǔ) polumorphos,含義是具有多種形式或形態(tài)的情形。在程序設(shè)計(jì)領(lǐng)域,一個(gè)廣泛認(rèn)可的定義是“ 一種將不同的特殊行為和單個(gè)泛化記號(hào)相關(guān)聯(lián)的能力”。和 純粹的面向?qū)ο蟪绦蛟O(shè)計(jì)語(yǔ)言不同,C++中的多態(tài)有著更廣泛的含義。除了常見的通過 類繼承和虛函數(shù)機(jī)制生效于運(yùn)行期的動(dòng)態(tài)多態(tài)( dynamic polymorphism )外,模板也允許將不同的特殊行為和單個(gè)泛化記號(hào)相關(guān)聯(lián),由于這種關(guān)聯(lián)處理于編譯期而非運(yùn)行期,因此被稱為靜態(tài)多態(tài)(static polymorphism)。 ?

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

            函數(shù)多態(tài)

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

            // overload_poly.cpp

            #include <iostream>
            #include <string>

            // 定義兩個(gè)重載函數(shù)

            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);??????????????? // 兩個(gè)整數(shù)相加
            ??? int s = my_add(1, "2");????????????? // 一個(gè)整數(shù)和一個(gè)字符串相加
            ??? std::cout << "i = " << i << "\n";
            ??? std::cout << "s = " << s << "\n";
            }?

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

            宏多態(tài)

            帶變量的宏可以實(shí)現(xiàn)一種初級(jí)形式的靜態(tài)多態(tài): ?

            // macro_poly.cpp

            #include <iostream>
            #include <string>

            // 定義泛化記號(hào):宏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);??????????????????????? // 兩個(gè)整數(shù)相加
            ??? std::string s = ADD(s1, s2);??????????????? // 兩個(gè)字符串“相加”
            ??? std::cout << "i = " << i << "\n";
            ??? std::cout << "s = " << s << "\n";
            }

            當(dāng)程序被編譯時(shí),表達(dá)式ADD(i1, i2)和ADD(s1, s2)分別被替換為兩個(gè)整數(shù)相加和兩個(gè)字符串相加的具體表達(dá)式。整數(shù)相加體現(xiàn)為求和,而字符串相加則體現(xiàn)為連接。程序的輸出結(jié)果符合直覺: ?

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

            動(dòng)態(tài)多態(tài)

            這就是眾所周知的的多態(tài)。現(xiàn)代面向?qū)ο笳Z(yǔ)言對(duì)這個(gè)概念的定義是一致的。其技術(shù)基礎(chǔ)在于 繼承機(jī)制和虛函數(shù)。例如,我們可以定義一個(gè)抽象基類Vehicle 和兩個(gè)派生于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的指針(或引用)來操縱具體對(duì)象。通過指向基類對(duì)象的指針(或引用)來調(diào)用一個(gè)虛函數(shù),會(huì)導(dǎo)致對(duì)被指向的具體對(duì)象之相應(yīng)成員的調(diào)用:

            // dynamic_poly_1.cpp

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

            // 通過指針run任何vehicle
            void run_vehicle(const Vehicle* vehicle)
            {
            ??? vehicle->run();??????????? // 根據(jù)vehicle的具體類型調(diào)用對(duì)應(yīng)的run()
            }

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

            此例中,關(guān)鍵的多態(tài)接口元素為 虛函數(shù)run()。由于 run_vehicle()的參數(shù)為指向基類Vehicle的指針 ,因而無法在編譯期決定使用哪一個(gè)版本的run()。在運(yùn)行期,為了分派函數(shù)調(diào)用,虛函數(shù)被調(diào)用的那個(gè)對(duì)象的完整動(dòng)態(tài)類型將被訪問。這樣一來,對(duì)一個(gè)Car對(duì)象調(diào)用 run_vehicle() 實(shí)際上將 調(diào)用Car::run(),而對(duì)于Airplane對(duì)象而言將調(diào)用Airplane::run()。

            或許動(dòng)態(tài)多態(tài)最吸引人之處在于處理異質(zhì)對(duì)象集合的能力: ?

            // dynamic_poly_2.cpp

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

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

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

            run_vehicles()中,vehicles[i]->run() 依據(jù)正被迭代的元素的類型而調(diào)用不同的成員函數(shù)。這從一個(gè)側(cè)面體現(xiàn)了面向?qū)ο缶幊田L(fēng)格的優(yōu)雅。

            靜態(tài)多態(tài)

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

            我們可以采用靜態(tài)多態(tài)機(jī)制重寫上一節(jié)的例子。這一次,我們不再定義vehicles類層次結(jié)構(gòu),相反,我們編寫彼此無關(guān)的具體類Car和Airplane(它們都有一個(gè)run()成員函數(shù)): ?

            // 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()應(yīng)用程序被改寫如下:?

            // 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();??????????? // 根據(jù)vehicle的具體類型調(diào)用對(duì)應(yīng)的run()
            }
            ?
            int main()
            {
            ??? Car car;
            ??? Airplane airplane;
            ??? run_vehicle(car);???????? // 調(diào)用Car::run()
            ??? run_vehicle(airplane);??? // 調(diào)用Airplane::run()
            }?

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

            我們無法再透明地處理異質(zhì)對(duì)象集合了,因?yàn)樗蓄愋投急仨氃诰幾g期予以決定。不過,為不同的vehicles引入不同的集合只是舉手之勞。由于無需再將集合元素局限于指針或引用,我們現(xiàn)在可以從執(zhí)行性能和類型安全兩方面獲得好處: ?

            // static_poly_2.cpp

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

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

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

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

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

            兩種多態(tài)機(jī)制的結(jié)合使用 ?

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

            // 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";
            ??? }
            };

            我們理想中的應(yīng)用程序可以編寫如下: ?

            // dscombine_poly.cpp

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

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

            // 為某種特定的aircrafts同質(zhì)對(duì)象集合進(jìn)行“空中加油”
            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;??????????????? // 異質(zhì)vehicles集合
            ??? v.push_back(&car1);
            ??? v.push_back(&airplane1);
            ??? v.push_back(&airship1);
            ??? run_vehicles(v);??????????????????????? // run不同種類的vehicles

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

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

            我們保留了類層次結(jié)構(gòu),目的是為了能 夠利用 run_vehicles()一致而優(yōu)雅地處理 異質(zhì)對(duì)象集合 vehicles的run問題。同時(shí),利用函數(shù)模板add_oil_to_aircrafts_in_the_sky<Aircraft>(),我們?nèi)匀豢梢蕴幚硖囟ǚN類的vehicles — aircrafts(包括airplanes和airships)的“空中加油”問題。其中,我們避開使用指針,從而在 執(zhí)行性能和類型安全兩方面達(dá)到了預(yù)期目標(biāo)。 ?

            結(jié)語(yǔ) ?

            長(zhǎng)期以來,C++社群對(duì)于多態(tài)的內(nèi)涵和外延一直爭(zhēng)論不休。在comp.object這樣的網(wǎng)絡(luò)論壇上,此類話題爭(zhēng)論至今仍隨處可見。曾經(jīng)有人將動(dòng)態(tài)多態(tài)稱為inclusion polymorphism,而將靜態(tài)多態(tài)稱為parametric polymorphism或parameterized polymorphism。 ?

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

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

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

            動(dòng)態(tài)多態(tài)只需要一個(gè)多態(tài)函數(shù),生成的可執(zhí)行代碼尺寸較小,靜態(tài)多態(tài)必須針對(duì)不同的類型產(chǎn)生不同的模板實(shí)體,尺寸會(huì)大一些,但生成的代碼會(huì)更快,因?yàn)闊o需通過指針進(jìn)行間接操作。靜態(tài)多態(tài)比動(dòng)態(tài)多態(tài)更加類型安全,因?yàn)槿拷壎ǘ急粰z查于編譯期。正如前面例子所示,你不可將一個(gè)錯(cuò)誤的類型的對(duì)象插入到從一個(gè)模板實(shí)例化而來的容器之中。此外,正如你已經(jīng)看到的那樣,動(dòng)態(tài)多態(tài)可以優(yōu)雅地處理異質(zhì)對(duì)象集合,而靜態(tài)多態(tài)可以用來實(shí)現(xiàn)安全、高效的同質(zhì)對(duì)象集合操作。 ?

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

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

            參考文獻(xiàn)

            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
            南京師范大學(xué)
            www.royaloo.com

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


            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            導(dǎo)航

            統(tǒng)計(jì)

            公告

            Dict.CN 在線詞典, 英語(yǔ)學(xué)習(xí), 在線翻譯

            常用鏈接

            留言簿(4)

            隨筆檔案

            文章分類

            文章檔案

            搜索

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            久久狠狠爱亚洲综合影院 | 国产精品美女久久久久AV福利| 久久91综合国产91久久精品| 久久久久久久久久久久久久| 精品久久综合1区2区3区激情| 99久久精品国内| 久久综合给合久久狠狠狠97色| 思思久久99热只有频精品66| 久久97久久97精品免视看| 婷婷综合久久中文字幕| 狠狠色婷婷综合天天久久丁香 | 久久乐国产综合亚洲精品| 91精品国产91久久综合| 久久综合88熟人妻| 日韩人妻无码精品久久久不卡| 欧美精品国产综合久久| 青青青青久久精品国产h久久精品五福影院1421| A级毛片无码久久精品免费| 人妻中文久久久久| 亚洲七七久久精品中文国产| 久久久久久久综合狠狠综合| 精品多毛少妇人妻AV免费久久| 77777亚洲午夜久久多人| 久久亚洲精品国产精品| 亚洲中文字幕无码久久2017| 欧美久久精品一级c片片| 国产午夜精品久久久久九九电影| segui久久国产精品| 国产一区二区精品久久凹凸| 欧美激情精品久久久久| 亚洲午夜精品久久久久久人妖| 色综合久久久久| 99热成人精品免费久久| 亚洲国产天堂久久综合网站| 97久久国产亚洲精品超碰热 | 久久久久亚洲AV无码网站| 无码人妻久久一区二区三区蜜桃| 中文无码久久精品| 久久se精品一区二区| 欧美一级久久久久久久大| 久久久久亚洲AV片无码下载蜜桃 |