使用引用。
C++:
void foo(stuff_s &what)
{
what.o.s = 4;
}
int main()
{
stuff_s SetToFour;
foo(SetToFour);
}
C:
void foo(stuff_s *what)
{
if (what == NULL) return;
what->o.s = 4;
}
int main(int argc, char *argv[])
{
stuff_s SetToFour;
foo(&SetToFour);
return 0; /* Because it's main in a strict C compiler. Ignore this. */
}
关于你的程序设计,如果你的数据真的非常不可知,我会推荐使用一个 void * 指针和一个对象类型标签,或者从一个基类派生一个类。
C++:
class base {
public:
int a;
virtual void do_whatever();
virtual int get_type() = 0; // Grab our type ID
};
class derived : public base {
public:
int b;
float c;
char *d;
virtual void do_whatever() { c = 4.0F; }
virtual int get_type() { return 1; }
};
struct stuff_s {
// ...in o
base *futs;
}
// Later on...
stuff_s foo;
switch (foo.o.futs->get_type()) {
case 0: // Base class
break;
case 1: // Class type 'derived'
derived *a = dynamic_cast<derived *>(foo.o.futs); // Dynamic cast lets us take a pointer to a base type and make it into a pointer to a derived type. Using our tag ID that we get from the virtual function, we can determine exactly which type to do.
a->b = 4;
break;
}
// This is roughly the same amount of code as the C version would use
如果你真的需要,我会提供一个 C 示例,但这太长了
编辑:我在下面看到它必须与 C 兼容。因此,我将扩展以包括最后一个代码的 C 等效项,还包括通过引用传递。请记住,这是概念性的:它会编译但不是很有用。
C:
/* This is a generic object. It has a type ID and a pointer, that is all that is needed. It can hold anything. */
struct generic_holder {
int type;
void *ptr;
};
/* This is an example struct it may point to. */
struct holder_one {
int a;
int b;
float c;
char *d;
int change_this;
};
/* This is another example struct. */
struct holder_two {
char best[50];
char worst[50];
int change_this;
};
struct stuff_s {
/* ...in .o */
generic_holder data;
};
/* Forward-declaration */
void set_to_four(stuff_s *foo);
/* Later on... */
int main(int argc, char* argv[])
{
stuff_s foo;
holder_two test_struct = { "C++", "Lisp", 0 }; // Best, worst. Haha.
foo.o.data.ptr = (void *)&test_struct; /* This makes it into a "generic pointer" by casting it to void */
foo.o.data.type = 2; /* = 2 because we are using holder_two */
/* We're going to use our function to set data in a generic object, passing by reference. This would work equally well on something of type holder_one, and can be expanded for data types you haven't thought of. */
set_to_four(&foo);
return 0;
}
/* This function will take a generic object and set the 'change_this' variable to 4 */
void set_to_four(stuff_s *foo)
{
holder_one *ptr1;
holder_two *ptr2;
if (foo == NULL) return; /* Obsessively check for invalid pointers */
assert(foo.o.data.ptr != NULL); /* Some people prefer to do checks only in debug, for speed. This does the same thing but only if debug is on. And it stops the program when it gets there if there is an error. It evaluates to nothing if it's a release build. */
switch(foo.o.data.type) {
case 1:
ptr1 = (holder_one *)foo.o.data.ptr;
ptr1->change_this = 4;
break;
case 2:
ptr2 = (holder_two *)foo.o.data.ptr;
ptr2->change_this = 4;
break;
default:
break;
}
}