C ++转换为派生指针或设计错误

时间:2016-02-27 17:40:10

标签: c++ templates inheritance casting

我对多态性有疑问

using namespace std;

class Base {
public:
Base(int v) { u = v; };
    virtual ~Base(){};
    int u;
    void f() { /* operations on u */ };
};

template<class T>
class Derived: public Base {
public:
    T t;
    Derived() { }
    void g() { std::cout << u; /* operations on t and u */ }
};

int main() {
    Base *b = new Base(1);
    b->f();
    if (b->u == 1) {
        Derived<int> *d = dynamic_cast<Derived<int> *>(b);
        d->g();
    }
    return 0;
}

使用d-> g()会有段错误。是否可以在演员后在Derived对象中访问u?该程序的目的是构造一个具有未知类型的类(关于此的信息只能在构造类对象之后才可用,例如读取jpg文件的类,深度信息事先不知道)。或者是否存在针对此类问题的设计模式?谢谢你的任何提示。

2 个答案:

答案 0 :(得分:2)

您的代码段错误不是因为Base::u中没有*b,而是因为dnullptr并且取消引用它会调用未定义的行为。根据规范,dynamic_cast<T*>(p)为您提供

  • 指向属于T的{​​{1}}对象的指针(如果有)或
  • a *p

由于nullptr未指向b类型的对象,因此您获得了Derived<int>。稍后,当您尝试使用nullptr时,您的程序会出现段错误。

请注意,如果nullptr为引用,则行为会有所不同。 dynamic_cast

  • 为您提供对dynamic_cast<T&>(r)所属T对象的引用(其中r为参考)或
  • r如果没有此类对象,则为throw类型的例外。

因此,您通常会通过以下任一方式使用std::bad_cast

  1. 如果您想测试对象的动态类型,并在某个dynamic_cast时对其进行处理:

    class
  2. 如果您(认为您)确定指针指向(动态)类型if (auto d = dynamic_cast<D*>(b)) { // We have a D object here (d != nullptr), use it. d->use(); } else { // We don't have a D object (d == nullptr) here. } 的对象:

    D
  3. 在您的情况下,似乎您有dynamic_cast<D&>(*b).use(); 某种约定应该暗示动态类型b->u == 1*b的约定,因此您可能会考虑Derived<int>参考。 (如果没有别的,它会在这里给你一个比“分段错误”更有用的错误信息。)当然,现在你知道dynamic_cast的行为,你可能会摆脱那个“约定”并测试动态直接通过dynamic_cast键入指针。无论如何,您首先必须解决Sam Varshavchikanswer中描述的问题。

    有关dynamic_cast的详细信息,请查看cppreference.com

答案 1 :(得分:1)

不,这是不可能的。

这是因为您构建了Base的实例,而不是Derived的实例。你可能打算这样做:

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

但这也不会起作用,因为Base没有默认的构造函数。

您将永远无法使用此代码实例化任何Derived<T>,因为Derived尝试使用Base的默认构造函数,但它没有之一。

dynamic_cast<T>并非用于创建类的新实例,并附加到现有类中,凭空捏造。它用于解析超级或子类的现有实例,它与动态转换的实例所属的类相关。