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

C++ cast to derived pointer or design mistake

本文关键字:错误 指针 派生 转换 C++      更新时间:2023-10-16

我有一个关于多态性的问题

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() 将存在段错误。 是否可以在强制转换后访问派生对象中的 u? 该程序的目的是构造一个未知类型的类(有关这方面的信息只有在构造了类对象之后才能获得,例如读取jpg文件的类,事先不知道深度信息)。 还是有针对这类问题的设计模式? 感谢您的任何提示。

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

  • 指向属于*p T对象的指针(如果有)或其他
  • nullptr .

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

请注意,如果dynamic_cast引用,则行为会有所不同。 dynamic_cast<T&>(r)意志

  • 为您提供对属于rT对象的引用(其中r是引用)或
  • 如果没有此类对象,则throw类型 std::bad_cast 的例外。

因此,您通常以以下任一方式使用 dynamic_cast

  1. 如果你想测试一个对象的动态类型,并在它达到一定class时用它做一些事情:

    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.
      }
    
  2. 如果您(认为您)确定指针指向(动态)类型的对象 D

    dynamic_cast<D&>(*b).use();
    

在您的情况下,您似乎有一个约定,即b->u == 1应该以某种方式暗示*b的动态类型是Derived<int>的,因此您可以考虑引用dynamic_cast。(如果没有别的,它会给你一个比这里的"分段错误"更有用的错误消息。当然,现在您知道dynamic_cast的行为方式,您可以摆脱该"约定"并直接通过指向指针dynamic_cast测试动态类型。无论如何,您首先必须解决Sam Varshavchik的答案中描述的问题。

查看 cppreference.com 以获取有关dynamic_cast的更多信息。

不,这是不可能的。

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

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

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

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

dynamic_cast<T> 不用于凭空创建附加到现有类的新实例。它用于解析超类或子类的现有实例,该实例与动态强制转换的实例所属的类相关。