前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++中的四种多态

C++中的四种多态

作者头像
ccf19881030
修改2021-04-03 21:13:33
1.4K0
修改2021-04-03 21:13:33
举报
文章被收录于专栏:ccf19881030的博客

本文转载自The Four Polymorphisms in C++

C++中的四种多态

当人们谈论C ++中的多态性时,通常是指通过基类指针或引用使用派生类的事情,这称为子类型多态性。 但是他们经常忘记,C ++中还有各种各样的其他多态性,例如参数多态性ad-hoc多态性强制多态性

这些多态性在C ++中也有不同的名称, - 子类型多态也称为运行时多态。 - 参数多态也称为编译时多态。 - 临时多态性也称为重载。 - 强制转换也称为(隐式或显式)强制转换。 在本文中,我将通过C ++语言的示例来说明所有多态性,并深入介绍为什么它们具有其他各种名称。

子类型多态性(运行时多态子类型多态是每个人在C ++中说“多态”时所理解的。 通过基类指针和引用使用派生类的能力。

这是一个例子。 假设您有各种猫科动物,例如这些猫科动物,

Polymorphic cats on a mat by James Halliday.
Polymorphic cats on a mat by James Halliday.

由于它们都是Felidae的生物学家族,并且都应该能够喵叫,因此可以将它们表示为从Felid基类继承并覆盖meow纯虚拟功能的类,

代码语言:javascript
复制
// file cats.h

class Felid {
public:
 virtual void meow() = 0;
};

class Cat : public Felid {
public:
 void meow() { std::cout << "Meowing like a regular cat! meow!\n"; }
};

class Tiger : public Felid {
public:
 void meow() { std::cout << "Meowing like a tiger! MREOWWW!\n"; }
};

class Ocelot : public Felid {
public:
 void meow() { std::cout << "Meowing like an ocelot! mews!\n"; }
};

现在,主程序可以通过Felid(基类)指针互换使用CatTigerOcelot

代码语言:javascript
复制
#include <iostream>
#include "cats.h"

void do_meowing(Felid *cat) {
 cat->meow();
}

int main() {
 Cat cat;
 Tiger tiger;
 Ocelot ocelot;

 do_meowing(&cat);
 do_meowing(&tiger);
 do_meowing(&ocelot);
}

在这里,主程序将指向cattigerocelot的指针传递给do_meowing函数,该函数期望指向Felid的指针。 由于它们都是猫科动物,因此程序会为每个猫科动物调用正确的meow函数,并且输出为:

代码语言:javascript
复制
Meowing like a regular cat! meow!
Meowing like a tiger! MREOWWW!
Meowing like an ocelot! mews!

由于种种原因,子类型多态也称为运行时多态。 多态函数调用的解析是在运行时通过虚拟表通过间接进行的。 另一种解释方式是,编译器不在编译时定位要调用的函数的地址,而是在程序运行时通过在虚拟表中取消引用右指针来调用该函数。

在类型理论中,它也称为包含多态性

参数多态性(编译时多态性)

参数多态性提供了一种对任何类型执行相同代码的方法。 在C ++中,参数多态性是通过模板实现的。

最简单的示例之一是泛型max函数,该函数找到两个参数中的最大值,

代码语言:javascript
复制
#include <iostream>
#include <string>

template <class T>
T max(T a, T b) {
 return a > b ? a : b;
}

int main() {
 std::cout << ::max(9, 5) << std::endl;     // 9

 std::string foo("foo"), bar("bar");
 std::cout << ::max(foo, bar) << std::endl; // "foo"
}

在这里,max函数在类型T上是多态的。但是,请注意,它不适用于指针类型,因为比较指针会比较内存位置而不是内容。 为了使它适用于指针,您必须专门针对指针类型使用模板,该模板不再是参数多态性,而是ad-hoc多态性。

由于参数多态性是在编译时发生的,因此也称为编译时多态性

临时多态性(重载)

临时多态性允许具有相同名称的函数对于每种类型的行为有所不同。 例如,给定两个整数和+运算符,它将它们加在一起。 给定两个std::strings,将它们连接在一起。 这称为重载

这是一个为intstring实现函数add的具体示例,

代码语言:javascript
复制
#include <iostream>
#include <string>

int add(int a, int b) {
 return a + b;
}

std::string add(const char *a, const char *b) {
 std::string result(a);
 result += b;
 return result;
}

int main() {
 std::cout << add(5, 9) << std::endl;
 std::cout << add("hello ", "world") << std::endl;
}

如果您专门研究模板,则临时多态性也会在C ++中出现。 返回上一个有关max函数的示例,这是您如何为两个char *编写max的方法,

代码语言:javascript
复制
template <>
const char *max(const char *a, const char *b) {
 return strcmp(a, b) > 0 ? a : b;
}

现在,您可以调用::max(“ foo”,“ bar”)来查找字符串“ foo”和“ bar”的最大值。

强制多态性(转换)

当将一个对象或原始类型强制转换为另一个对象类型或原始类型时,会发生强制转换。 例如,

代码语言:javascript
复制
float b = 6; // int gets promoted (cast) to float implicitly
int a = 9.99 // float gets demoted to int implicitly

当使用C的类型转换表达式,例如(unsigned int *)(int)或C ++的static_castconst_castreinterpret_castdynamic_cast时,会发生显式转换。

如果类的构造函数不是explicit的,则也会发生强制转换,例如,

代码语言:javascript
复制
#include <iostream>

class A {
 int foo;
public:
 A(int ffoo) : foo(ffoo) {}
 void giggidy() { std::cout << foo << std::endl; }
};

void moo(A a) {
 a.giggidy();
}

int main() {
 moo(55);     // prints 55
}

如果将A的构造函数设为explict,则将不再可能。 使构造函数显式以避免意外转换始终是一个好主意。

同样,如果类为T类型定义了转换运算符,则可以在需要T类型的任何地方使用它。

例如,

代码语言:javascript
复制
class CrazyInt {
 int v;
public:
 CrazyInt(int i) : v(i) {}
 operator int() const { return v; } // conversion from CrazyInt to int
};

CrazyInt定义了一个转换运算符来键入int。 现在,如果我们有一个以int作为参数的print_int函数,我们还可以将CrazyInt类型的对象传递给它,

代码语言:javascript
复制
#include <iostream>

void print_int(int a) {
 std::cout << a << std::endl;
}

int main() {
 CrazyInt b = 55;
 print_int(999);    // prints 999
 print_int(b);      // prints 55
}

我前面讨论的子类型多态实际上也是强制性多态,因为派生类已转换为基类类型。

玩转所有有关多态性的新知识,下次再见!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/02/26 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • C++中的四种多态
    • 子类型多态性(运行时多态子类型多态是每个人在C ++中说“多态”时所理解的。 通过基类指针和引用使用派生类的能力。
      • 参数多态性(编译时多态性)
        • 临时多态性(重载)
          • 强制多态性(转换)
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档