如何从void *指针动态转换?

时间:2017-08-30 01:54:37

标签: c++ void-pointers dynamic-cast

from pyspark.sql.types import LongType, StringType, StructField, StructType, BooleanType, ArrayType, IntegerType

customSchema = StructType(Array(
    StructField("project", StringType, true),
    StructField("article", StringType, true),
    StructField("requests", IntegerType, true),
    StructField("bytes_served", DoubleType, true)))

pagecount = sc.read.format("com.databricks.spark.csv")
         .option("delimiter"," ")
         .option("quote","")
         .option("header", "false")
         .schema(customSchema)
         .load("dbfs:/databricks-datasets/wikipedia-datasets/data-001/pagecounts/sample/pagecounts-20151124-170000")

每当我尝试动态地将class BASE { public: virtual ~BASE() {} void lamp() { cout << "\nBASE CLASS"; } }; class DERIVED : public BASE { public: void fun(); }; void DERIVED::fun() { cout << "\nDERIVED CLASS!"; } int main() { BASE * pbase = new DERIVED; //BASE CLASS POINTER void * vbase = pbase; //VOID POINTER TAKING BASE POINTER DERIVED * pder; //DERIVED CLASS POINTER //pder = static_cast<DERIVED *>(vbase); //THIS WORKS pder = dynamic_cast<DERIVED *>(vbase); //THIS DOESN'T pder->lamp(); pder->fun(); return 0; } 指针强制转换为派生类指针时,我都会收到以下错误:

  

不能使用dynamic_cast'vbase'(类型'void *')来输入'class DERIVED *'(source不是指向类的指针)

我搜索了StackOverflow,并通过在基类中实现虚函数来避免错误。我究竟做错了什么? 这有可能吗?

我的总体意图是使用void*指针将任何传入的Object类型转换为Derived类类型。我希望你明白我的意思。

例如:

void*

我应该能够将任何类型的指针传递给void dynamicCast(void * vptr) { BASE * pbase = new DERIVED; DERIVED * pder; pder = dynamic_cast<DERIVED *>(vbase); } 函数,它应该转换为派生类指针。

4 个答案:

答案 0 :(得分:1)

您无法在dynamic_cast上使用void *

根据规范,dynamic_cast<T>(v)

  

如果T是指针类型,则v应为指向完整类类型的指针的prvalue,结果是类型为T的prvalue ...

您应该做的是让所有类派生自相同的多态基类(至少有一个虚函数)BASE,并使用BASE *而不是void *

答案 1 :(得分:1)

您的通用链接列表应如下所示:

class Node
{
    Node* next;
    void* vdata;
}

这是唯一严格要求的数据结构,但您可能需要循环列表或基本节点来跟踪列表的结尾或双向链接列表。

来电者通知你一个空*,你创建一个新节点,设置“vdata”并将节点添加到你的列表中。

答案 2 :(得分:1)

将指向对象类型的指针转​​换为指向void的指针时,该void指针的有效转换为返回其原始类型。您无法在指向dynamic_cast的指针上使用void,因为void不是多态类型,因此您使用static_cast进行操作。像这样:

BASE *pbase = new DERIVED;
void *vbase = pbase; // Ok; implicit conversion to void*
BASE *pbase1 = static_cast<BASE*>(vbase); // the cast is required

当您回到指向BASE的指针后,您可以使用dynamic_cast将其转换为指向派生类型的指针:

DERIVED *pder = dynamic_cast<DERIVED*>(pbase1);

答案 3 :(得分:1)

我认为存在设计或/和理解问题

正如所解释的那样,dynamic_cast无法void*

为什么呢?由于dynamic_cast需要一些运行时类型信息(RTTI)来执行转换(有关详细信息,请参阅this link)。仅从void*开始,C ++代码就无法知道这些信息的位置。最小的是使用指向具有此类RTTI信息的对象的指针。

此信息已创建并限制在具有至少一个虚拟方法的任何类中。如果没有虚拟方法,则不包括此信息。这就是工作的原因:

struct A
{
};

struct B : A
{
};

int main()
{
  B  b;
  A *a = &b;

  dynamic_cast<B *>(a);  // YOUR COMPILE TIME ERROR
}

修复是向A添加虚拟方法。这里我添加了一个虚拟析构函数this is generally a good thing

struct A
{
   virtual ~A() = default;
};

struct B : A
{
};

int main()
{
  B  b;
  A *a = &b;

  dynamic_cast<B *>(a);  // OK
}

另请注意,dynamic_cast可让您检查转化是否合法。

例如,我们可以添加 C 类并检查:

struct C 
{
};

int main()
{
  B  b;
  A *a = &b;

  assert(dynamic_cast<B *>(a)!=nullptr); // OK
  assert(dynamic_cast<C *>(a)==nullptr); // OK can not cast A to C 
}

这种运行时操作不是免费的。如果你搜索最大速度可以使用这个技巧:

assert(dynamic_cast<B *>(a)!=nullptr);
B* b=static_cast<B*>(a);

在调试模式下,您将检查一切是否正常,并在发布模式下使用-DNDEBUG标记删除assert,您只会使用static_cast