zoukankan      html  css  js  c++  java
  • C++多态的学习

    几天前看了多态,感觉不怎么好!因为就是虚函数的重写

    但是,看看大牛们的文章,才感觉到压力!多态果然不一样,今天把他们的日志转载过来共那些没有入门,(多态方面)的同学学习!

    1. 函数多态

         也就是我们常说的函数重载(function overloading)。基于不同的参数列表,同一个函数名字可以指向不同的函数定义: 

    // overload_poly.cpp

    #include <iostream>
    #include <string>

    // 定义两个重载函数

     1 int my_add(int a, int b)
    2 {
    3 return a + b;
    4 }
    5 int my_add(int a, std::string b)
    6 {
    7 return a + atoi(b.c_str());
    8 }
    9 int main()
    10 {
    11 int i = my_add(1, 2); // 两个整数相加
    12 int s = my_add(1, "2"); // 一个整数和一个字符串相加
    13 std::cout << "i = " << i << "\n";
    14 std::cout << "s = " << s << "\n";
    15 }



         根据参数列表的不同(类型、个数或兼而有之),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()。

    2. 宏多态

         带变量的宏可以实现一种初级形式的静态多态:  
    // macro_poly.cpp

    #include <iostream>
    #include <string>

    // 定义泛化记号:宏ADD
    #define ADD(A, B) (A) + (B);

    1 int main()
    2 {
    3 int i1(1), i2(2);
    4 std::string s1("Hello, "), s2("world!");
    5 int i = ADD(i1, i2); // 两个整数相加
    6 std::string s = ADD(s1, s2); // 两个字符串“相加”
    7 std::cout << "i = " << i << "\n";
    8 std::cout << "s = " << s << "\n";
    9 }



         当程序被编译时,表达式ADD(i1, i2)和ADD(s1, s2)分别被替换为两个整数相加和两个字符串相加的具体表达式。整数相加体现为求和,而字符串相加则体现为连接。程序的输出结果符合直觉:  
         1 + 2 = 3
         Hello, + world! = Hello, world!

    3. 动态多态

         这就是众所周知的的多态。现代面向对象语言对这个概念的定义是一致的。其技术基础在于继承机制和虚函数。例如,我们可以定义一个抽象基类Vehicle和两个派生于Vehicle的具体类Car和Airplane:

     1 // dynamic_poly.h
    2 #include <iostream>
    3 // 公共抽象基类Vehicle
    4 class Vehicle
    5 {
    6 public:
    7 virtual void run() const = 0;
    8 };
    9 // 派生于Vehicle的具体类Car
    10 class Car: public Vehicle
    11 {
    12 public:
    13 virtual void run() const
    14 {
    15 std::cout << "run a car\n";
    16 }
    17 };
    18 // 派生于Vehicle的具体类Airplane
    19 class Airplane: public Vehicle
    20 {
    21 public:
    22 virtual void run() const
    23 {
    24 std::cout << "run a airplane\n";
    25 }
    26 };
    27 客户程序可以通过指向基类Vehicle的指针(或引用)来操纵具体对象。通过指向基类对象的指针(或引用)来调用一个虚函数,会导致对被指向的具体对象之相应成员的调用:
    28 // dynamic_poly_1.cpp
    29 #include <iostream>
    30 #include <vector>
    31 #include "dynamic_poly.h"
    32 // 通过指针run任何vehicle
    33 void run_vehicle(const Vehicle* vehicle)
    34 {
    35 vehicle->run(); // 根据vehicle的具体类型调用对应的run()
    36 }
    37 int main()
    38 {
    39 Car car;
    40 Airplane airplane;
    41 run_vehicle(&car); // 调用Car::run()
    42 run_vehicle(&airplane); // 调用Airplane::run()
    43 }
    44 此例中,要害的多态接口元素为虚函数run()。由于run_vehicle()的参数为指向基类Vehicle的指针,因而无法在编译期决定使用哪一个版本的run()。在运行期,为了分派函数调用,虚函数被调用的那个对象的完整动态类型将被访问。这样一来,对一个Car对象调用run_vehicle(),实际上将调用Car::run(),而对于Airplane对象而言将调用Airplane::run()。
    45 或许动态多态最吸引人之处在于处理异质对象集合的能力:
    46 // dynamic_poly_2.cpp
    47 #include <iostream>
    48 #include <vector>
    49 #include "dynamic_poly.h"
    50 // run异质vehicles集合
    51 void run_vehicles(const std::vector<Vehicle*>& vehicles)
    52 {
    53 for (unsigned int i = 0; i < vehicles.size(); ++i)
    54 {
    55 vehicles[i]->run(); // 根据具体vehicle的类型调用对应的run()
    56 }
    57 }
    58 int main()
    59 {
    60 Car car;
    61 Airplane airplane;
    62 std::vector<Vehicle*> v; // 异质vehicles集合
    63 v.push_back(&car);
    64 v.push_back(&airplane);
    65 run_vehicles(v); // run不同类型的vehicles
    66 }



         在run_vehicles()中,vehicles[i]->run()依据正被迭代的元素的类型而调用不同的成员函数。这从一个侧面体现了面向对象编程风格的优雅。

    4. 静态多态

         假如说动态多态是通过虚函数来表达共同接口的话,那么静态多态则是通过“彼此单独定义但支持共同操作的具体类”来表达共同性,换句话说,必须存在必需的同名成员函数。  
         我们可以采用静态多态机制重写上一节的例子。这一次,我们不再定义vehicles类层次结构,相反,我们编写彼此无关的具体类Car和Airplane(它们都有一个run()成员函数): 

    View Code
     1 // static_poly.h
    2 #include <iostream>
    3 //具体类Car
    4 class Car
    5 {
    6 public:
    7 void run() const
    8 {
    9 std::cout << "run a car\n";
    10 }
    11 };
    12 //具体类Airplane
    13 class Airplane
    14 {
    15 public:
    16 void run() const
    17 {
    18 std::cout << "run a airplane\n";
    19 }
    20 };
    21 run_vehicle()应用程序被改写如下:
    22
    23 // static_poly_1.cpp
    24 #include <iostream>
    25 #include <vector>
    26 #include "static_poly.h"
    27 // 通过引用而run任何vehicle
    28 template <typename Vehicle>
    29 void run_vehicle(const Vehicle& vehicle)
    30 {
    31 vehicle.run(); // 根据vehicle的具体类型调用对应的run()
    32 }
    33
    34 int main()
    35 {
    36 Car car;
    37 Airplane airplane;
    38 run_vehicle(car); // 调用Car::run()
    39 run_vehicle(airplane); // 调用Airplane::run()
    40 }
    41 现在Vehicle用作模板参数而非公共基类对象(事实上,这里的Vehicle只是一个符合直觉的记号而已,此外别无它意)。经过编译器处理后,我们最终会得到run_vehicle<Car>()和 run_vehicle<Airplane>()两个不同的函数。这和动态多态不同,动态多态凭借虚函数分派机制在运行期只有一个run_vehicle()函数。
    42 我们无法再透明地处理异质对象集合了,因为所有类型都必须在编译期予以决定。不过,为不同的vehicles引入不同的集合只是举手之劳。由于无需再将集合元素局限于指针或引用,我们现在可以从执行性能和类型安全两方面获得好处:
    43 // static_poly_2.cpp
    44 #include <iostream>
    45 #include <vector>
    46 #include "static_poly.h"
    47 // run同质vehicles集合
    48 template <typename Vehicle>
    49 void run_vehicles(const std::vector<Vehicle>& vehicles)
    50 {
    51 for (unsigned int i = 0; i < vehicles.size(); ++i)
    52 {
    53 vehicles[i].run(); // 根据vehicle的具体类型调用相应的run()
    54 }
    55 }
    56 int main()
    57 {
    58 Car car1, car2;
    59 Airplane airplane1, airplane2;
    60 std::vector<Car> vc; // 同质cars集合
    61 vc.push_back(car1);
    62 vc.push_back(car2);
    63 //vc.push_back(airplane1); // 错误:类型不匹配
    64 run_vehicles(vc); // run cars
    65 std::vector<Airplane> vs; // 同质airplanes集合
    66 vs.push_back(airplane1);
    67 vs.push_back(airplane2);
    68 //vs.push_back(car1); // 错误:类型不匹配
    69 run_vehicles(vs); // run airplanes
    70 }



    5. 两种多态机制的结合使用 

         在一些高级C++应用中,我们可能需要结合使用动态多态和静态多态两种机制,以期达到对象操作的优雅、安全和高效。例如,我们既希望一致而优雅地处理vehicles的run问题,又希望“安全而高效”地完成给飞行器(飞机、飞艇等)进行“空中加油”这样的高难度动作。为此,我们首先将上面的vehicles类层次结构改写如下: 

     1 // dscombine_poly.h
    2 #include <iostream>
    3 #include <vector>
    4 // 公共抽象基类Vehicle
    5 class Vehicle
    6 {
    7 public:
    8 virtual void run() const = 0;
    9 };
    10 // 派生于Vehicle的具体类Car
    11 class Car: public Vehicle
    12 {
    13 public:
    14 virtual void run() const
    15 {
    16 std::cout << "run a car\n";
    17 }
    18 };
    19 // 派生于Vehicle的具体类Airplane
    20 class Airplane: public Vehicle
    21 {
    22 public:
    23 virtual void run() const
    24 {
    25 std::cout << "run a airplane\n";
    26 }
    27
    28 void add_oil() const
    29 {
    30 std::cout << "add oil to airplane\n";
    31 }
    32 };
    33 // 派生于Vehicle的具体类Airship
    34 class Airship: public Vehicle
    35 {
    36 public:
    37 virtual void run() const
    38 {
    39 std::cout << "run a airship\n";
    40 }
    41
    42 void add_oil() const
    43 {
    44 std::cout << "add oil to airship\n";
    45 }
    46 };



    我们理想中的应用程序可以编写如下:
      

     1 // dscombine_poly.cpp
    2 #include <iostream>
    3 #include <vector>
    4 #include "dscombine_poly.h"
    5 // run异质vehicles集合
    6 void run_vehicles(const std::vector<Vehicle*>& vehicles)
    7 {
    8 for (unsigned int i = 0; i < vehicles.size(); ++i)
    9 {
    10 vehicles[i]->run(); // 根据具体的vehicle类型调用对应的run()
    11 }
    12 }
    13 // 为某种特定的aircrafts同质对象集合进行“空中加油”
    14 template <typename Aircraft>
    15 void add_oil_to_aircrafts_in_the_sky(const std::vector<Aircraft>& aircrafts)
    16 {
    17 for (unsigned int i = 0; i < aircrafts.size(); ++i)
    18 {
    19 aircrafts[i].add_oil();
    20 }
    21 }
    22 int main()
    23 {
    24 Car car1, car2;
    25 Airplane airplane1, airplane2;
    26 Airship airship1, airship2;
    27 std::vector<Vehicle*> v; // 异质vehicles集合
    28 v.push_back(&car1);
    29 v.push_back(&airplane1);
    30 v.push_back(&airship1);
    31 run_vehicles(v); // run不同种类的vehicles
    32 std::vector<Airplane> vp; // 同质airplanes集合
    33 vp.push_back(airplane1);
    34 vp.push_back(airplane2);
    35 add_oil_to_aircrafts_in_the_sky(vp); // 为airplanes进行“空中加油”
    36 std::vector<Airship> vs; // 同质airships集合
    37 vs.push_back(airship1);
    38 vs.push_back(airship2);
    39 add_oil_to_aircrafts_in_the_sky(vs); // 为airships进行“空中加油”
    40 }



         我们保留了类层次结构,目的是为了能够利用run_vehicles()一致而优雅地处理异质对象集合vehicles的run问题。同时,利用函数模板add_oil_to_aircrafts_in_the_sky<Aircraft>(),我们仍然可以处理特定种类的vehicles — aircrafts(包括airplanes和airships)的“空中加油”问题。其中,我们避开使用指针,从而在执行性能和类型安全两方面达到了预期目标。

  • 相关阅读:
    sed 简明教程
    简明 Vim 练级攻略
    AWK 简明教程
    TCP 的那些事儿(下)
    TCP 的那些事儿(上)
    CentOS 7系统安装配置图解教程
    Google Chrome谷歌/火狐/Safari浏览器开发者工具基本使用教程
    《Ext JS模板与组件基本框架图----组件》
    ExtJS关于组件Component生命周期
    《Ext JS模板与组件基本知识框架图----模板》
  • 原文地址:https://www.cnblogs.com/leisure/p/duotai.html
Copyright © 2011-2022 走看看