快捷搜索:

C++多态技术

择要

本文描述了C++中的各类多态性。重点阐述了面向工具的动态多态和基于模板的静态多态,并初步探究了两种技巧的结合应用。

关键词

多态 承袭 虚函数 模板 宏 函数重载 泛型编程 泛型模式

导言

多态(polymorphism)一词最初滥觞于希腊语polumorphos,含义是具有多种形式或形态的情形。在法度榜样设计领域,一个广泛认可的定义是“一种将不合的特殊行径和单个泛化暗号相关联的能力”。和纯挚的面向工具法度榜样设计说话不合,C++中的多态有着更广泛的含义。除了常见的经由过程类承袭和虚函数机制生效于运行期的动态多态(dynamic polymorphism)外,模板也容许将不合的特殊行径和单个泛化暗号相关联,因为这种关联处置惩罚于编译期而非运行期,是以被称为静态多态(static polymorphism)。

事实上,带变量的宏和函数重载机制也容许将不合的特殊行径和单个泛化暗号相关联。然而,习气上我们并不将它们展现出来的行径称为多态(或静态多态)。本日,当我们谈及多态时,假如没有明确所指,默认便是动态多态,而静态多态则是指基于模板的多态。不过,在这篇以C++各类多态技巧为主题的文章中,我们首先照样回首一下C++社群争辩已久的另一种“多态”:函数多态(function polymorphism),以及更不常提的“宏多态(macro polymorphism)”。

函数多态

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

// overload_poly.cpp

#include

#include

// 定义两个重载函数

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

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

#include

// 定义泛化暗号:宏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

当法度榜样被编译时,表达式ADD(i1, i2)和ADD(s1, s2)分手被调换为两个整数相加和两个字符串相加的详细表达式。整数相加表现为乞降,而字符串相加则表现为连接。法度榜样的输出结果相符直觉:

1 + 2 = 3

Hello, + world! = Hello, world!

动态多态

这便是众所周知的的多态。今世面向工具说话对这个观点的定义是同等的。其技巧根基在于承袭机制和虚函数。例如,我们可以定义一个抽象基类Vehicle和两个派生于Vehicle的详细类Car和Airplane:

// dynamic_poly.h

#include

// 公共抽象基类Vehicle

class Vehicle

{

public:

virtual void run() const = 0;

};

// 派生于Vehicle的详细类Car

class Car: public Vehicle

{

public:

virtual void run() const

{

std::cout

客户法度榜样可以经由过程指向基类Vehicle的指针(或引用)来操纵详细工具。经由过程指向基类工具的指针(或引用)来调用一个虚函数,会导致对被指向的详细工具之响应成员的调用:

静态多态

假如说动态多态是经由过程虚函数来表达合营接口的话,那么静态多态则是经由过程“彼此零丁定义但支持合营操作的详细类”来表达合营性,换句话说,必须存在必需的同名成员函数。

我们可以采纳静态多态机制重写上一节的例子。这一次,我们不再定义vehicles类层次布局,相反,我们编写彼此无关的详细类Car和Airplane(它们都有一个run()成员函数):

// static_poly.h

#include

//详细类Car

class Car

{

public:

void run() const

{

std::cout

run_vehicle()利用法度榜样被改写如下:

// static_poly_1.cpp

#include

#include

#include "static_poly.h"

// 经由过程引用而run任何vehicle

template

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()和 run_vehicle()两个不合的函数。这和动态多态不合,动态多态凭借虚函数分派机制在运行期只有一个run_vehicle()函数。

// dscombine_poly.h

#include

#include

// 公共抽象基类Vehicle

class Vehicle

{

public:

virtual void run() const = 0;

};

// 派生于Vehicle的详细类Car

class Car: public Vehicle

{

public:

virtual void run() const

{

std::cout

我们抱负中的利用法度榜样可以编写如下:

// dscombine_poly.cpp

#include

#include

#include "dscombine_poly.h"

// run异质vehicles聚拢

void run_vehicles(const std::vector& vehicles)

{

for (unsigned int i = 0; i run();         // 根据详细的vehicle类型调用对应的run()

}

}

// 为某种特定的aircrafts同质工具聚拢进行“空中加油”

template

void add_oil_to_aircrafts_in_the_sky(const std::vector& aircrafts)

{

for (unsigned int i = 0; iv;        // 异质vehicles聚拢

v.push_back(&car1);

v.push_back(&airplane1);

v.push_back(&airship1);

run_vehicles(v);            // run不合种类的vehicles

std::vector vp;        // 同质airplanes聚拢

vp.push_back(airplane1);

vp.push_back(airplane2);

add_oil_to_aircrafts_in_the_sky(vp);   // 为airplanes进行“空中加油”

std::vector 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(),我们仍旧可以处置惩罚特定种类的vehicles — aircrafts(包括airplanes和airships)的“空中加油”问题。此中,我们避开应用指针,从而在履行机能和类型安然两方面达到了预期目标。

您可能还会对下面的文章感兴趣: