C++:在 C 语言中传递指向模板类的指针

C++: Passing pointer to template class around in C

本文关键字:指针 语言 C++      更新时间:2023-10-16

我正在为我的库编写一个C包装器API。

我通常将我的C++对象作为 C 中的void*传递。每个对象的公共函数自然都有访问包装器函数。C 代码访问本机C++类成员。

昨天,有人在 IRC 上提到,我不应该将指向C++模板类的指针传递为 C 语言中的void*,因为这很危险。这是真的吗?指向普通C++类的指针与指向模板类的指针有何不同?

谢谢!

这是

假的。模板没有普通类所没有的特殊属性重新转换。确保你总是使用适当的石膏,你会没事的。

这与模板与普通类无关,但是如果您的类具有多重继承,则应始终从相同的类型开始,然后再转换为void*,并且在转换回时也是如此。指针的地址将根据指针类型的父类而更改。

class ParentA
{
    // ...
    int datumA;
};
class ParentB
{
    // ...
    int datumB;
};
class Derived : public ParentA, public ParentB
{
    // ...
};
int main()
{
    Derived d;
    ParentA * ptrA = &d;
    ParentB * ptrB = &d;
    assert((void*)ptrA == (void*)ptrB); // asserts!
}

将一些指针Foo*投射到void*上,然后在相同类型的Foo*上恢复始终是安全的。但是,在使用继承时,应特别注意。不应通过void*指针进行向上转换/向下转换。请考虑以下代码:

#include <cassert>
class Parent
{
    int bar;
};
class Derived : public Parent
{
    virtual void foo() { }
};
int main()
{
    Derived d;
    Derived* ptr_derived = &d;
    void *ptr_derived_void = ptr_derived;
    Derived*    ptr_derived_from_void = (Derived*)ptr_derived_void;
    assert(ptr_derived_from_void == ptr_derived);   //that's OK
    Parent* ptr_parent = ptr_derived;   //upcast
    Parent* ptr_parent_from_void = (Parent*)ptr_derived_void;   //upcast?
    assert(ptr_parent_from_void == ptr_parent); //that's not OK
    return 0;
}

这篇文章还显示了通过void*投射的一些问题。

使用类AB作为模板参数实例化的模板类涉及编译器创建两个单独的类来专门处理这些各自的类型。在许多方面,这就像一个智能强类型预处理器宏。手动复制粘贴两个分别对AB进行操作的独立"正常"类没有什么不同。所以没有。

唯一的危险方法是,如果您尝试投射最初的内容:

MyClass<A>

MyClass<B>

如果A不是 B ,因为它们可能具有不同的内存布局。

指针

就是:指向数据的指针。指针的"类型"实际上对任何事情都没有区别(在编译时(,它只是为了代码的可读性和可维护性。

例如:

 Foo<a> *x = new Foo<a>();
 void *y = (void*)x;
 Foo<a> *z = (Foo<a>*)y;

完全有效,不会引起任何问题。强制转换指针类型时的唯一问题是,当您忘记指针实际引用的基础数据类型时,可能会遇到取消引用问题。

如果你在任何地方传递 void*,只需注意保持类型完整性。

不要执行以下操作:

Foo<a> *x = new Foo<a>();
void *z = (void*)x;
//pass around z for a while, then mistakenly...
Foo<b> *y = (Foo<b>*)z;

意外!