【问题标题】:Isn't there essentially only one "kind" of polymorphism in C++?C++ 中本质上不是只有一种“类型”的多态性吗?
【发布时间】:2016-04-20 12:40:45
【问题描述】:

那就是:函数重载

我的意思是

base_ptr->derived_class_method()

本质上是

derived_class_method(base* this_ptr)

这是通过函数重载实现的多态性。

通过模板的多态性也可以这样说,包括CRTP等。

因此,考虑到最广泛的实现,所有“各种”多态性似乎都归结为函数重载

还是我错过了什么?

【问题讨论】:

  • 你会说,编程语言可以有哪些多态性?有没有什么特别的东西,你认为,在 C++ 中不存在?
  • 您遗漏了一些东西。您可以从this 开始。 (顺便说一句,您的示例非常不清楚。如果this 参数始终具有相同的类型,它是如何重载的?您是否将重载与覆盖混淆了?)
  • 从概念上讲,这个问题确实有道理。
  • 您要么将重载与覆盖混淆,要么否认其中之一的存在,以及 Liskov 替换原则。
  • 这是术语问题“我可以称之为函数重载吗?” - 从某种角度来看 - 是的。这实际上意味着什么吗?没有。

标签: c++ polymorphism overloading


【解决方案1】:

本质上不是只有一种“种类”

取决于您如何定义“种类”。 Wikipedia 将多态性分为 3 类:Ad hoc、参数化和子类型化。所有这些类型的多态性都存在于 C++ 中。

那就是:函数重载

在 C++ 语言的上下文中,单词function overloading 具有特定的含义。有了这个意思,模板和虚函数都不能称为函数重载

但是,抽象地说是的,所有多态性(在 C++ 中,也许在一般的计算机科学中)归结为选择一个函数实现而不是另一个。

【讨论】:

    【解决方案2】:

    您遗漏了一些东西,但主要是一个关键区别:重载是编译时,而覆盖(即virtual)可以是运行时。通过重载,您可以这样做:

    void make_a_sound(Cat const& cat)
    {
      std::cout << cat << ": meow" << std::endl;
    }
    
    void make_a_sound(Dog const& dog)
    {
      std::cout << dog << ": wurf" << std::endl;
    }
    
    int main()
    {
      Cat c;
      Dog d;
      make_a_sound(c);
      make_a_sound(d);
    }
    

    但你不能这样做:

    class Animal
    {
      virtual void make_a_sound() = 0;
    };
    
    void make_a_sound(std::vector<Animal*> const& animals)
    {
      for (Animal* a : animals)
        a->make_a_sound();
    }
    

    在第一个示例中,编译器将在编译时选择要调用的正确函数。您可以不同地命名这两个函数(即make_a_sound_catmake_a_sound_dog),它的工作原理相同,能够重用相同的名称只是为了方便。

    然而,在第二个示例中,编译器生成代码,以便在运行时,您的程序将找出每种动物的确切性质并调用正确的方法。

    【讨论】:

      【解决方案3】:

      基本上分为三种多态

      1.特设
      2. 参数化
      3. 子类型




      1。特设:

      Ad-hoc 多态性允许具有相同名称的函数对每种类型执行不同的操作。 (这是你举的例子)

      例子:

      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;
      }
      

      2。参数:

      参数多态性提供了一种为任何类型执行相同代码的方法。它是通过 C++ 中的模板实现的。 (所以给定定义,你可以说它也是一种自动函数重载)

      3。子类型:

      子类型是通过基类指针和引用使用派生类来实现的。所以在实践中,我们使用子类和虚拟方法进行子类型化。 (这不是函数重载

      class Mammal 
      {
      public:
          Mammal() {};
          virtual ~Mammal() {};
      
          virtual std::string SendLoudNoise()
          {
              std::string str("I am a generic mammal");
              return str;
          }
      };
      class Dog : public Mammal {
      public:
          Dog() {};
          virtual ~Dog() {};
      
          std::string SendLoudNoise()
          {
              std::string str("Woof woof!");
              return str;
          }
      };
      class Cat : public Mammal {
      public:
          Cat() {};
          virtual ~Cat() {};
      
          std::string SendLoudNoise()
          {
              std::string str("--- Twitch my tail ---");
              return str;
          }
      };
      
      int main()
      {
          Mammal* pAnimal[2] = { new Dog, new Cat};
      
          for (int i = 0 ; i < 2; ++i)
          {
              std::cout << pAnimal[i]->SendLoudNoise() << std::endl;
              delete pAnimal[i];
          }
      
          return 0;
      }
      

      您无法通过函数重载来实现子类型化。因为它是“运行时多态性”。

      【讨论】:

        【解决方案4】:

        在 C++ 中有三个。

        主要区别在于“多态”的独立程度。

        • 重载是临时多态性。

        它是临时的,因为您只是使用相同的名称来表示几个不同的功能,不需要以任何方式关联。

        例子:

        int   foo(int);
        void  foo(const std::string&, double);
        
        • 函数模板提供参数多态性。

        这些仅取决于其参数的接口(广义上的“接口”;不是 Java 意义上的)。

        例子:

        template<typename T>
        T id(T t)
        {
            return t;
        }
        

        这为每个T 定义一个函数,如果T 是可复制构造的。

        一个有效的问题是“这不是一种自动重载吗?”,答案是 C++ 中的区别不是很大。
        在其他语言中,id 可能实际上只是一个函数,可用于任何类型。

        • “虚拟函数” - 覆盖 - 是子类型化。

        这些都与特定的类型层次结构紧密相关。

        您会注意到,重载要求多态具有不同的原型,而其他两个要求原型相同。

        此外,虚函数(通常)在运行时绑定,而其他两个总是在编译时绑定(在 C++ 中)。

        【讨论】:

          【解决方案5】:

          这里是 C++ 中所有可能的多态性的完整列表:

          1. 特设多态性
            • 强制多态性(隐式转换)
            • 重载多态性,可以是
              • 函数重载
              • 运算符重载
          2. 通用多态性
            • 包含多态性(子类型化)
            • 参数或泛型多态性

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2013-04-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2023-03-24
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多