我最近一直在思考这个问题。我们大多数人都知道,在C
中,为了创建结构,通常会在其前面加上typedef
,以避免在引用对象之前调用struct
关键字。当然,C仅限于结构而非类。为了弥补这一点,C倾向于使用专用于结构的全局函数来创建面向对象的方法
例如:
typedef struct{
int foo;
float bar;
char* baz;
} SomeStruct;
Vs。
struct AnotherStruct {
int foo;
float bar;
char* baz;
};
在函数中声明该类型的对象时,AnotherStruct
前面必须有前缀关键字struct
。例如:
int main( ... )
{
struct AnotherStruct obj1; //correct
SomeStruct obj2; //correct
struct SomeStruct obj3; //bad
AnotherStruct obj4; //bad
}
在面向对象方法方面:
typedef struct {
//member variables here
} SomeStruct;
SomeStruct* SomeStruct_New( int a, int b, int c )
{
SomeStruct* obj = calloc( sizeof( SomeStruct ), 1 ); //not sure if that's correct -- been a while since I've used calloc.
obj.a = a;
obj.b = b;
obj.c = c;
return obj;
}
void SomeStruct_Free( SomeStruct* free )
{
free( free );
}
这些函数在没有包装的情况下很容易实现——我只是为了举例而使用它们。我的观点是,考虑到你已经可以在C++中创建一个结构,它不需要typedef
在没有struct
关键字的情况下声明,并且使用与这些结构相关的非封装函数来实现面向对象的方法,我很想知道C++中的C编码方法是否有任何优势,这将包括使用静态全局函数作为私有成员函数以及将返回指向对象的指针的全局函数构造函数
这主要是出于好奇,因为有时我觉得采取C方法只是为了采取它,但这可能只是一件优惠的事情。
很难理解这个问题的要点。在我看来,你的主要问题是:
- "简单"数据+函数
比好
- 对象
在某些情况下。
没有相当于。
除了例外(!),你用C++表达的任何代码都可以用C表达。这只是一个语法糖的问题,使C++对应物更容易阅读在反对者加入潮流之前,是的,虚拟表可以在C.中模拟。
尽管如此,我还是宁愿使用C++。编译器检查封装(private
)、编译器驱动的重载选择、编译器样板(模板)。它只是句法糖,但却是如此甜蜜的糖。
话虽如此:
class Foo {
Foo() {}
friend Foo build(int a, int b);
friend int getA(Foo const& foo);
friend int getB(Foo const& foo);
int a;
int b;
};
可以被认为是面向对象的。
EDIT:多态性的简单和伪示例。
#include <stdio.h>
// Interface
typedef void (*FunctionPrint)(void const*);
typedef struct {
FunctionPrint print;
} PrinterInterface;
void print(void const* item, PrinterInterface const* pi) {
(*pi->print)(item);
}
// Foo
typedef struct { int a; } Foo;
void printFoo(void const* arg) {
Foo const* foo = (Foo const*)arg;
printf("Foo{%d}n", foo->a);
}
PrinterInterface const FooPI = { &printFoo };
// Bar
typedef struct { char* a; } Bar;
void printBar(void const* arg) {
Bar const* bar = (Bar const*)arg;
printf("Bar{"%s"}n", bar->a);
}
PrinterInterface const BarPI = { &printBar };
// Main
int main() {
Foo foo = { 1 };
Bar bar = { "Hello, World!" };
print(&foo, &FooPI);
print(&bar, &BarPI);
}
结果:
Foo{1}
Bar{"Hello, World!"}
据我所知,之所以存在这样的声明,只是因为一些常见的头文件(主要来自操作系统API:think to windows.h或"xlib.h")必须在C和C++程序中使用,这些程序都是不可预测的C和C++版本。
如果这样的API按照今天重写(注意:API本身,而不仅仅是接口),它们可能不会有这样的声明。是一种"混蛋编码",它使API开发人员确信内存映射(当结构绑定到硬件或外部二进制格式时很重要)和"幻数定义",这些定义在不同语言的不同标头中永远不会重复。
不,我认为在C++中没有任何情况是有意义的。
想要使用C方法的最明显的情况是中断和线程回调函数。但这些可以在C++中写成私有静态成员,这是我们更喜欢的。
一般来说,在极少数情况下,甚至从C或C++中的函数返回指针都是有意义的。你的例子不是很好的OO,你强迫类的用户在不需要的时候使用动态分配
在实时嵌入式编程中,当你不希望调用任何构造函数,从而完全避免类时,我可以想出一些例子,但在这种情况下,你可能根本不会使用C++。
就在最近,我开始使用Horde3D,它(或多或少)实现了您所描述的内容。在C++中内部实现,在C中公开一个简单的API。
这种方法对像我这样希望通过外语接口重用引擎的人很有吸引力。我正致力于将引擎耦合到SWI-Prolog,由于Prolog不遵循面向对象程序的方向,所以使用(例如)OGRE接口没有任何好处。OGRE有更多的功能,但简单也有其优点。。。