我有一个具有如下类型的 C 库:
typedef struct {
// ...
} mytype;
mytype *mytype_new() {
mytype *t = malloc(sizeof(*t));
// [Initialize t]
return t;
}
void mytype_dosomething(mytype *t, int arg);
我想提供 C++ 包装器以提供更好的语法。但是,我想避免拥有单独分配的包装器对象的复杂性。我有一个相对复杂的对象图,其内存管理已经比我想要的更复杂(对象以所有可访问对象保持事件状态的方式重新计数)。此外,C 库将使用指向此对象的指针回调到 C++,并且为每个 C->C++ 回调构建新包装对象的成本(因为 C 不知道包装器)对我来说是 Not Acceptable 。
我的总体方案是:
class MyType : public mytype {
public:
static MyType* New() { return (MyType*)mytype_new(); }
void DoSomething(int arg) { mytype_dosomething(this, arg); }
};
这将为 C++ 程序员提供更好的语法:
// C Usage:
mytype *t = mytype_new();
mytype_dosomething(t, arg);
// C++ Usage:
MyType *t = MyType::New();
t->DoSomething(arg);
小谎是我正在将 mytype*
(使用 malloc()
分配)向下转换为 MyType*
,这是骗人的。但是如果 MyType
没有成员也没有虚函数,看来我应该能够依赖于 sizeof(mytype) == sizeof(MyType)
,除此之外 MyType
没有编译器可以生成任何类型引用的实际数据。
因此,尽管这可能违反了 C++ 标准,但我很想认为我可以逃脱惩罚,即使在各种编译器和平台上也是如此。
我的问题是:
- 有没有可能,运气好,这实际上并没有违反 C++ 标准?
- 有谁能想到我在使用这样的方案时可能遇到的现实世界中的实际问题吗?
编辑:@James McNellis 问了一个很好的问题,为什么我不能将 MyType 定义为:
class MyType {
public:
MyType() { mytype_init(this); }
private:
mytype t;
};
原因是我有 C 回调,它会使用 mytype*
回调到 C++,我希望能够直接将其转换为 MyType*
而无需不得不复制。
最佳答案
您正在将 mytype*
向下转型为 MyType*
,这是合法的 C++。但这里有问题,因为 mytype*
指针实际上并不指向 MyType
。它实际上指向一个mytype
。因此,如果您向下转换它执行 MyType
并尝试访问它的成员,它几乎肯定不会工作。即使没有数据成员或 virtual
函数,您将来也可能会遇到代码异味。
即使它没有违反 C++ 标准(我认为确实如此),我仍然会对代码有点怀疑。通常,如果您要包装 C 库,“现代 C++ 方式”是通过 RAII idiom :
class MyType
{
public:
// Constructor
MyType() : myType(::mytype_new()) {}
// Destructor
~MyType() { ::my_type_delete(); /* or something similar to this */ }
mytype* GetRawMyType() { return myType; }
const mytype* GetConstRawMyType() const { return myType; }
void DoSomething(int arg) { ::mytype_dosomething(myType, int arg); }
private:
// MyType is not copyable.
MyType(const MyType&);
MyType& operator=(const MyType&);
mytype* myType;
};
// Usage example:
{
MyType t; // constructor called here
t.DoSomething(123);
} // destructor called when scope ends
关于c++ - 我可以摆脱这个 C++ 向下转型的谎言吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7182614/