【问题标题】:what's polymorphic type in C++?C++中的多态类型是什么?
【发布时间】:2011-01-03 04:37:29
【问题描述】:

我在一篇文章中发现“static_cast 用于非多态类型转换,而 dynamic_cast 用于多态类型转换”。我知道 int 和 double 不是多态类型。

不过,我也发现可以在基类和派生类之间使用static_cast。这里的多态类型是什么意思?有人说多态类型是指带有虚函数的基类。那正确吗?这是唯一的情况吗?还有什么?谁能为我详细说明一下?

【问题讨论】:

    标签: c++


    【解决方案1】:

    首先,这篇文章并不完全正确。 dynamic_cast 检查对象的类型并可能失败,static_cast 不检查并且很大程度上要求程序员知道他们在做什么(尽管它会为某些人发出编译错误严重错误),但它们可能用于多态情况。 (dynamic_cast 有一个额外的要求,即至少有一个涉及的类型具有虚方法。)

    简而言之,C++ 中的多态是通过单独定义的接口使用对象。该接口是基类,并且几乎总是只有在它具有虚拟方法时才有用。

    然而,在没有任何虚方法的情况下存在多态性是罕见但可能的;这通常表明设计不好或必须满足外部要求,因此,没有办法给出适合这里的好例子。 (不幸的是,“当你看到它时,你就会知道何时使用它”,这是我能给你的最好建议。)

    多态示例:

    struct Animal {
      virtual ~Animal() {}
      virtual void speak() = 0;
    };
    
    struct Cat : Animal {
      virtual void speak() { std::cout << "meow\n"; }
    };
    
    struct Dog : Animal {
      virtual void speak() { std::cout << "wouf\n"; }
    };
    
    struct Programmer : Animal {
      virtual void speak() {
        std::clog << "I refuse to participate in this trite example.\n";
      }
    };
    

    稍微练习一下上面的课程——另见我的generic factory example

    std::auto_ptr<Animal> new_animal(std::string const& name) {
      if (name == "cat") return std::auto_ptr<Animal>(new Cat());
      if (name == "dog") return std::auto_ptr<Animal>(new Dog());
      if (name == "human") return std::auto_ptr<Animal>(new Programmer());
      throw std::logic_error("unknown animal type");
    }
    
    int main(int argc, char** argv) try {
      std::auto_ptr<Animal> p = new_animal(argc > 1 ? argv[1] : "human");
      p->speak();
      return 0;
    }
    catch (std::exception& e) {
      std::clog << "error: " << e.what() << std::endl;
      return 1;
    }
    

    也可以use polymorphism without inheritance,因为它确实是一种设计技术风格。 (我拒绝在这里使用流行语 pattern... :P)

    【讨论】:

    • 任何可以多态使用的类型。
    • -1 所有这些可能都是正确且有用的,但问题尚未得到明确回答。永远不应该被接受。
    【解决方案2】:

    static_cast 可以在指向相关类的指针之间执行转换,不仅可以从派生类到其基类,还可以从基类到其派生类。这确保了如果转换了正确的对象,至少类是兼容的,但在运行时不执行安全检查来检查正在转换的对象是否实际上是目标类型的完整对象。因此,由程序员来确保转换是安全的。另一方面,避免了 dynamic_cast 类型安全检查的开销。

    static_cast 还可用于执行任何其他也可以隐式执行的非指针转换,例如基本类型之间的标准转换:

    double d=3.14159265;
    int i = static_cast<int>(d); 
    

    dynamic_cast 只能与对象的指针和引用一起使用。其目的是确保类型转换的结果是所请求类的有效完整对象。

    因此,当我们将一个类强制转换为其基类之一时,dynamic_cast总是成功

    // dynamic_cast
    #include <iostream>
    #include <exception>
    using namespace std;
    
    class CBase { virtual void dummy() {} };
    class CDerived: public CBase { int a; };
    
    int main () {
     try {
        CBase * pba = new CDerived;
        CBase * pbb = new CBase;
        CDerived * pd;
    
        pd = dynamic_cast<CDerived*>(pba);
        if (pd==0) cout << "Null pointer on first type-cast" << endl;
    
        pd = dynamic_cast<CDerived*>(pbb);
        if (pd==0) cout << "Null pointer on second type-cast" << endl;
    
        } catch (exception& e) {cout << "Exception: " << e.what();}
        return 0;
     }
    

    兼容性说明:dynamic_cast 需要运行时类型信息 (RTTI) 来跟踪动态类型。一些编译器支持此功能作为默认禁用的选项。必须启用此功能才能使用 dynamic_cast 进行运行时类型检查才能正常工作。

    虚拟函数负责 C++ 中的运行时多态性。具有至少一个虚函数的类具有多态类型。

    Read More....

    也阅读this。上面写的很清楚A class that declares or inherits a virtual function is called a polymorphic class.

    【讨论】:

    • 非常感谢您的回答。但我不认为你回答了我的问题。我的问题是什么是多态类型。不是 static_cast 和 dynamic_cast 的区别
    • 类至少有一个虚函数。你已经在你的问题中回答了。
    • 如果您没有其他方法可以使虚拟化:使 dtor 成为虚拟化,无论如何它都应该在这种示例中。
    • 我没有从您的代码中复制它。我从我发布的链接中复制了它。我已经要求 skydoor 从我提供的链接中阅读更多详细信息。
    • 啊,是他们在这里错误地使用了try-catch!
    【解决方案3】:

    嗯,答案很简单。具有至少一个虚函数的类称为多态类型。这也只能是一个析构函数。

    所以下面是一个'多态类型'。

    struct Test {
      virtual ~Test();
    };
    

    【讨论】:

    • 所以没有虚函数的类总是可以使用static_cast进行强制转换?
    • @skydoor:不,请阅读我的帖子。 static_cast 可以在指向相关类的指针之间进行转换,不仅可以从派生类到其基类,还可以从基类到其派生类。
    • 反之,dynamic_cast 只能对具有至少一个虚函数的类执行!
    【解决方案4】:

    我认为完整的短语是“多态类型casting”。没错,static_cast 适用于与继承无关的类型(double - int 等),而其他答案则指出了强制转换的工作方式。

    我不认为该声明暗示了神话中的多态类型的存在——只是 static_cast 也适用于不相关的类型。不过,该声明有点令人困惑,最好澄清一下。

    【讨论】:

      【解决方案5】:

      我认为我们总是将任何类的析构函数定义/声明为虚拟的,尤其是在继承树中。那么我们可以说继承树中几乎所有的类都是多态的。

      【讨论】:

        猜你喜欢
        • 2010-10-25
        • 2014-09-27
        • 2011-02-11
        • 2014-11-06
        • 2013-05-27
        • 2017-11-03
        • 2011-11-15
        • 2023-03-28
        • 2018-11-21
        相关资源
        最近更新 更多