阅读后
我想知道以下解决方法是否有效,以及它在编译器级别的最深层含义。
// foo.h
typedef struct foo
{
int i;
#ifdef __cplusplus
foo(int _i) : i(_i) {};
#endif
} foo;
// bar.c
#include "foo.h"
foo bar;
bar.i = 1;
// bar.cpp
#include "foo.h"
foo bar(2);
在我看来,这是一个利用" struct polymorphism"的一个很好的技巧,能够保持与C遗留代码的可移植性,但我感觉在某种程度上我现在正在使用两个不同的类型。
答案 0 :(得分:4)
从您的问题中查看此struct
定义:
typedef struct foo
{
int i;
#ifdef __cplusplus
foo(int _i) : i(_i) {};
#endif
} foo;
当使用针对同一平台的C和C ++编译器进行编译时,可能导致相同的内存表示形式。但你应该从不依赖于此。 C ++编译器看到的类型比C编译器看到的类型多一个成员,因此它们基本上是不同的类型。因此,将它们视为相同的是未定义的行为。如果这可以按预期工作,那就是纯粹的运气,并且可能随时中断。
正如已经评论的那样,引入virtual
函数几乎可以保证打破它,因为C ++编译器需要将vtable
存储在struct
中的某个位置。但即使没有它,还有许多其他方式可以打破,例如因为编译器会添加不同的填充。只是不要这样做。
您可以做的是使用 plain C struct
并在需要时在C ++中添加包装类。
答案 1 :(得分:3)
这两种是不同的类型。编译为C会产生与编译为C ++不同的类型。同时在同一个程序中使用它们(即将C和C ++对象链接在一起成为一个exectuable),结果将是未定义的行为,因为违反了C ++中的单定义规则。
这不是保持C和C ++之间可移植性的方法。行为是未定义的,所以你可能会很幸运,并发现它可以按你的意愿运行。但是,同样地,行为是未定义的,因此可能无效。
答案 2 :(得分:2)
如果您想确保与C库的兼容性,那就不是这样了。
您想要定义是-a foo
的类型,并且可以将其传递给库函数。就这样做,继承:
class shiny_foo : foo {
// Member functions and anything that changes the object layout.
};
extern "C" void c_bar_func(foo *);
void cxx_bar_func(shiny_foo& obj) {
// do stuff
c_bar_func(&obj); // obj *is-a* foo as well, remember
}