1

I have a C-header file with 100s of data structs. I want to make a superclass that each data struct inherits from. How to do that? Should I parse the header file? Reflection?

Because each C data struct is a public class, I could just make a superclass and... then what? I should not go in manually and explicitly make every struct inherit from the superclass?

Brutalizer
  • 13
  • 4
  • 3
    What real problem are you trying to solve? – Mark B Jul 09 '12 at 16:07
  • I have an API with lot of C data structs. They are sent into a server with "send_transaction (datastruct_nr41)" which is a C function call. Now I want to make a C++ application. Each data struct message will have some common functions (serialize, deserialize, etc). So I thought I make a class out of each C data struct, with a common superclass, having common functions. Was this clearer? – Brutalizer Jul 09 '12 at 16:10
  • @Brutalizer: And how would the base class *serialize* without actual knowledge of which derived type it is being called on? Or do you mean to just add the interface and implement it in derived types? If you intend on implementing it only on derived types, why not create a parallel hierarchy that stores the C structs (composition) and implements the functions? – David Rodríguez - dribeas Jul 09 '12 at 16:27
  • I dont understand parallell hierarchy. Do you have some example code? I am planning to serialize with the factory pattern. I get a binary blob from the server, what kind of data struct is it? Solution: http://www.gamedev.net/page/resources/_/technical/multiplayer-and-network-programming/why-pluggable-factories-rock-my-multiplayer-world-r841 – Brutalizer Jul 09 '12 at 16:59
  • Wait, you want the structs to inherit from a class, and still be able to send them through a C function (`send_transaction`)? – Shahbaz Jul 09 '12 at 16:59
  • Yes. I want to send data structs through a C function. But all the data structs will have some common functionality, for instance serialize. So I might make a superclass which contains serialize(), which means every data struct can serialize(). – Brutalizer Jul 09 '12 at 22:59

4 Answers4

2

For your particular use case, I would leave the C code as is, and just create whatever solution you need in C++ leveraging the C code. You can for example, create a parallel hierarchy with a base that defines the interface that includes serialize() and deserialize() and each derived type storing one of the C structs and implementing the serialization of that particular type.

You can also tackle this completely externally, by providing templated serialize/deserialize functions that are defined for each one of the C structs... Inheritance is one of the most often abused features of C++.

The best solution will depend on how you intend on using the code, but I would avoid rewriting the C code (i.e. scripting an editor to rewrite the C header into a C++ solution) as that will effectively branch out of the C library and you will need to maintain two separate branches if you ever need to extend it C side.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • I dont really understand what you mean. – Brutalizer Jul 09 '12 at 17:02
  • `struct BaseSerializable { virtual void serialize() = 0; }; struct XSerializer { C_type_X value; virtual void serialize() { ... }; };` No need to modify the C types, just store a member of the type inside your C++ wrapper... but this might not be a good solution either, it all depends on the rest of the design. – David Rodríguez - dribeas Jul 09 '12 at 17:28
  • I dont understand how to use this code. The C_type_X is a data struct? And then what? How do I use this code with the data structs? – Brutalizer Jul 09 '12 at 23:08
  • @Brutalizer: Ahem... instead of editing the C types to add inheritance relationships you can do that externally with your own type hierarchy where you can just *use* the existing C code by storing the C structs and using existing code that manages them. You might want to consider digging into some of the recommended programming books. – David Rodríguez - dribeas Jul 10 '12 at 00:46
  • Which programming books cover this? I am a Java programmer and have read C++ books - but I am not familiar with C++ yet. I know what I want to do, but not really how to do it in C++. That is the reason I need to see some code so I understand. Meta descriptions is always easy to understand, but how do you do it in practice in C++? As Linus Torvalds says "talk is cheap, show me the code!" ;o) – Brutalizer Jul 10 '12 at 09:07
  • Ok, it was quite late yesterday so I did not understand anything. But now I have looked at it, and you suggest something like the below, yes? XSerializer myThing; myThing.serialize(); myThing.value.getInt(); – Brutalizer Jul 10 '12 at 09:20
  • @Brutalizer: You can even offer the whole interface in the wrapper: `myThing.getInt()` that would be implemented as `return value.aInt;` (or whatever value is obtained from the C class). If you need to interact with C code that handles the object outside of your class, then you can provide an accessor to the object. As of books, I would try to read a couple of books on design which are the ones that will give you a broader view. – David Rodríguez - dribeas Jul 10 '12 at 11:48
2

If you have a bunch of structs:

The obvious answer is to make clever use of search and replace to make them inherit from the new base class. It wouldn't be able to access the members of the structs, but you could store pointers to them all in containers

struct base {
    int dostuff() const {std::cout << "thing";}
};
struct thing1 : public base {
    int size;
};
//otherstructs inheriting from base
int main() {
    std::vector<std::unique_ptr<base>> objects;
    objects.push_back(std::unique_ptr<base>(new thing1()));
    objects[1].dostuff();
}

If making the base class thing is too hard, you might try adding functions via a wrapper class instead. You won't be able to store pointers to these in a container, but they can access members, as long as the structs have similar members.

struct thing1 {
    int size;
};
//other unchanged structs
template<class mystruct>
struct wrapper : mystruct {
    int getsize() {return mystruct.size;}
};

int main() {
     wrapper<thing1> mything1;
     std::cout << mything1.size << mything1.getsize();
}

Or, if you're just adding methods, make them separate functions:

struct thing1 {
    int size;
};
//other unchanged structs
template<class T>
int getsize(const T& obj) {return obj.size;}

int main() {
     thing1 mything1;
     std::cout << mything1.size << getsize(mything1);
}
BenMorel
  • 34,448
  • 50
  • 182
  • 322
Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
  • I like your explanation, providing some code to make it clearer. Thanks. So, I create one wrapper for each data struct? Inside each wrapper class, there is a reference to the data struct itself, and also some functions? But that is code duplication, is there not an easier solution? In particular, I want to use this pattern. I get a binary blob from the server, and I need to find out which data struct it is. This is one solution: http://www.gamedev.net/page/resources/_/technical/multiplayer-and-network-programming/why-pluggable-factories-rock-my-multiplayer-world-r841 – Brutalizer Jul 09 '12 at 16:58
  • So which solution is more elegant? This one, or the one by ForEveR? – Brutalizer Jul 09 '12 at 17:05
  • ForEveR is suggesting that you make hundreds of new structs, I think templates are a way better idea _if_ they work for your situation. The template idea doesn't allow base pointers, where his idea would. – Mooing Duck Jul 09 '12 at 17:12
  • Base pointer, you mean, a pointer to the data struct? I dont really understand this code. How would I use it with a C data struct? Could you provide some more code? But if it is possible to use one single template class instead of making 100s of classes, this is neater? How do you do make your code look like C++ code, with some tags? Which tags? – Brutalizer Jul 09 '12 at 23:11
  • @Brutalizer: I mean if the structs all inherit from the same base, then you can store pointers to these structs in a single container. I have added lots of code to show the three ideas. The first one requires 100s of new classes, the second two don't. They all have pros and cons. – Mooing Duck Jul 09 '12 at 23:27
  • Ok, this is a good answer. Thank you. The code made everything much clearer. I will probably just use some functions, and no superclasses at all. KISS. But... the problem with functions is it is not really object oriented, which feels a bit weird to use. But I guess I need to wrap them into a class and some member methods that hide the C functions. BTW, I just got 5 in reputation? This is the first time I use this forum. :o) Hmmm.... How do I thank you? Is there a button to give you reputation? – Brutalizer Jul 10 '12 at 09:27
  • If you mark an answer as "the best" they get lots of rep, and if you click the "this is helpful" upvote button, that gives a medium amount of rep as well. (Be sure to upvote all helpful answers) Having functions as not members is fine, don't worry overmuch about it. – Mooing Duck Jul 10 '12 at 16:51
  • Ok, thanks. I will thank all answers soon, gotta go for one hour. A last question: In example no 2, it says "You won't be able to store pointers to these in a container, but they can access members, as long as the structs have similar members". Why can I not store pointers? – Brutalizer Jul 11 '12 at 09:39
  • you wont be able to put pointers to different types of structs in the same container because they have no types in common. They have a template in common, but a template is not a type. – Mooing Duck Jul 11 '12 at 14:54
1

There is no reflection in C/C++, and there is no one base class for other classes in C++, so this isn't an easy task. You can manually make every class you have inherit from the superclass as you suggested, or you can create a base class and then create a new structure for each data structs, which inherits it's concrete data struct and also the base class. For example http://liveworkspace.org/code/7e06e0374ef41bc4aeeafd55ae143527 or http://liveworkspace.org/code/7e06e0374ef41bc4aeeafd55ae143527.
I think manually making each struct inherit from the base class in your C-header file is more efficient.

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
ForEveR
  • 55,233
  • 2
  • 119
  • 133
  • So... For example http://liveworkspace.org/code/7e06e0374ef41bc4aeeafd55ae143527 or http://liveworkspace.org/code/7e06e0374ef41bc4aeeafd55ae143527 or some template wrapper as @Mooing Duck suggest. – ForEveR Jul 09 '12 at 16:56
  • Hey! This is good! Thanks! Wow! I think this is something for me. Are there any solutions I can learn from? :o) Thanks! – Brutalizer Jul 09 '12 at 17:01
  • So I need to create one XXX_Based class for every data struct, yes? And because I have 100 data structs, I need to manually make these XXX_Based classes? But it is a nice solution. I like it. – Brutalizer Jul 09 '12 at 17:05
  • Yeah, it`s only one worked solution, or make a template wrapper, but template wrapper will be inherited from your struct, so, wrapper will have access to S1 data, but in your code you should use this wrapper object, not S1 struct. – ForEveR Jul 09 '12 at 17:11
1

I have never heard of structs using inheritance - it might be standard practice somewhere but all the examples of inheritance have been using a class - will it create a hardship to change the struct to a class? This could be confusing as I tend to think "C" when I see a struct.

Also are you sure that with inheritance, you still need 100's of structs or classes? If they really don't have duplicate data, that is OK, but if there are duplicated fields, it might be a good idea to have them inherit from each other to remove the duplicate fields.

A B
  • 4,068
  • 1
  • 20
  • 23
  • The API uses different C data structs, and it has some C functions to send in data structs to the back end. My C++ application will send in messages to the back end server. These messages are the C data structs. But all the C data structs will have some common functions. How would I handle this? C header file: struct A; struct B; struct C; ... send_datastruct (void *); How would you handle this situation in C++? Make a common super class, that each C data struct inherits from? Any suggestions? – Brutalizer Jul 09 '12 at 16:27
  • You can override base class functions in C++ see this URL http://stackoverflow.com/questions/4869216/calling-derived-class-function-from-base-class – A B Jul 09 '12 at 16:43