C++ - 将基类指针转换为派生类指针

39
#include <iostream>
using namespace std;

class Base {
public:
  Base() {};
  ~Base() {};
};

template<class T>
class Derived: public Base {
  T _val;
public:
  Derived() {}
  Derived(T val): _val(val) {}
  T raw() {return _val;}
};

int main()
{
  Base * b = new Derived<int>(1);
  Derived<int> * d = b;
  cout << d->raw() << endl;
  return 0;
}

我现在有一些多态性的问题,上面的代码总结了所有的内容。我创建了一个Base类指针,并将一个新的派生模板类的指针放入其中。然后我为派生模板类创建了一个新的指针,并希望它引用基类指针所指向的内容。即使Base指针(b)指向Derived,也无法将引用传递给Derived类指针(d),因为编译器说“从Base *到Derived<int> *没有已知的转换”。那么有没有什么技巧或替代方法能够实现呢?谢谢提前。

1
http://www.boost.org/doc/libs/1_34_0/libs/conversion/cast.htm - StevieG
2
你所描述的转换被称为向下转型 - ComicSansMS
3个回答

63
您必须将基础类型更改为多态类型:
class Base {
public:
    Base() {};
    virtual ~Base(){};
};

为了将某个父类型强制转换为某个派生类型,应使用 dynamic_cast:
Base *b = new Derived<int>(1);
Derived<int> *d = dynamic_cast<Derived<int> *>(b);

在这里使用 dynamic_cast 是为了检查类型转换是否可行。如果没有必要进行此检查(因为转换不会失败),也可以使用 static_cast

Base *b = new Derived<int>(1);
Derived<int> *d = static_cast<Derived<int> *>(b);

11
+1 注意基类需要虚函数以供 dynamic_cast 使用。 - Neil Kirk
2
不要说你“必须”使用dynamic_cast。你并不需要这样做。 - Neil Kirk
@NeilKirk 正确,但应该使用 dynamic_cast,因为它会检查是否可以进行转换。 - Abrixas2
@NeilKirk Visual Studio 2015只允许使用dynamic_cast,并将static_cast标记为错误。返回+1。 - Orwellophile
为什么基类需要是多态的? - Jagdish
1
@JagsVG 除非你想对它们执行 dynamic_cast<>,否则它们不需要。 - Fureeish

5
你可以使用dynamic_cast。
Derived<int> * d = dynamic_cast<Derived<int> *>(b);

如果转换失败(基指针不指向所请求的派生类型),则返回 null。
但是,为了使 dynamic_cast 起作用,您的基类必须至少有一个虚函数。我建议您将析构函数设置为虚函数(这也可以防止删除对象时出现其他潜在问题)。
使用 dynamic_cast 可能表明您代码的设计存在问题。
请注意,如果您确信基指针指向您的派生类型,则可以将其替换为 static_cast,它会稍微快一些。个人而言,我更喜欢一般的额外安全检查。

5

试试这个:

Derived<int> * d = static_cast<Derived<int>* >(b);

缺点是,您可以强制转换为Base()实例的类,然后d->raw()将未定义(可能会导致段错误)。如果可能出现这种情况,请使用dynamic_cast并至少拥有一个基本虚函数(在处理多态性时,析构函数必须是虚拟的)。

虚函数在底层是使用虚表指针实现的。该指针也可用于标识类的真实类型。dynamic_cast使用此指针来检查是否可以进行此转换,并在转换时带来小的额外开销。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接