【发布时间】:2011-01-03 04:37:29
【问题描述】:
我在一篇文章中发现“static_cast 用于非多态类型转换,而 dynamic_cast 用于多态类型转换”。我知道 int 和 double 不是多态类型。
不过,我也发现可以在基类和派生类之间使用static_cast。这里的多态类型是什么意思?有人说多态类型是指带有虚函数的基类。那正确吗?这是唯一的情况吗?还有什么?谁能为我详细说明一下?
【问题讨论】:
标签: c++
我在一篇文章中发现“static_cast 用于非多态类型转换,而 dynamic_cast 用于多态类型转换”。我知道 int 和 double 不是多态类型。
不过,我也发现可以在基类和派生类之间使用static_cast。这里的多态类型是什么意思?有人说多态类型是指带有虚函数的基类。那正确吗?这是唯一的情况吗?还有什么?谁能为我详细说明一下?
【问题讨论】:
标签: c++
首先,这篇文章并不完全正确。 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)
【讨论】:
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++ 中的运行时多态性。具有至少一个虚函数的类具有多态类型。
也阅读this。上面写的很清楚A class that declares or inherits a virtual function is called a polymorphic class.
【讨论】:
嗯,答案很简单。具有至少一个虚函数的类称为多态类型。这也只能是一个析构函数。
所以下面是一个'多态类型'。
struct Test {
virtual ~Test();
};
【讨论】:
dynamic_cast 只能对具有至少一个虚函数的类执行!
我认为完整的短语是“多态类型casting”。没错,static_cast 适用于与继承无关的类型(double - int 等),而其他答案则指出了强制转换的工作方式。
我不认为该声明暗示了神话中的多态类型的存在——只是 static_cast 也适用于不相关的类型。不过,该声明有点令人困惑,最好澄清一下。
【讨论】:
我认为我们总是将任何类的析构函数定义/声明为虚拟的,尤其是在继承树中。那么我们可以说继承树中几乎所有的类都是多态的。
【讨论】: