简体   繁体   中英

Dynamic structures in C++

I am running a simulation in which I have objects of a class which use different models. These models are randomly selected for some objects of the class and specifically decided for some objects too. These objects communicate with each other for which I am using structures (aka struct) in C++ which has some

  1. standard variables and
  2. some additional variables which depends on models which the objects communicating with each other have.

So, how can I do this?

Thanks in advance.

You can hack around with:

  • the preprocessor;
  • template meta-programming;
  • inheritance/polymorphism.

Each gives a different way of producing a different user-defined type, based on different kinds of conditions.

Without knowing what you're trying to accomplish, this is the best I can do.

There are several common approaches for "dynamic" attributes/properties in languages, and a few that tend to work well in C++.

For example, you can make a C++ class called " MyProperties " that has a sparse set of values, and your MyStructureClass would have its well-known members, plus a single MyProperties instance which may have zero-or-more values.

Similarly, languages like Python and Perl make extensive use of Associative Arrays/Dictionaries/Hashes to achieve this: The (string) key uniquely identifies the value. In C++, you can index your MyProperties class with a string or any type you want (after overloading the operator[]() ), and the value can be a string , a MyVariant , or any other pointer-or-type that you want to inspect. The values are dynamically added to the parent container as they are assigned (eg, the class "remembers" the last value it is given, uniquely identified by key).

Finally, in the "olden days", what you describe was commonly done for distributed application processing: You defined a C- struct with "well-known" (typed) fields/members, and the last field was a char* member. Then, that char* member would identify the start of a serialized stream of bytes that were also part of that struct (you merely serialized that array of chars when you marshalled the struct across systems). In the context of C++, you could similarly extract your values dynamically from that char* stream buffer on-access-demand (which logically should be "owned" by the class). This worked for marshalling across systems because the size of the struct was the size of everything (including the last char* member), but the "allocation" for that struct was much larger (eg, the size of the struct itself, which was logically a "header", plus a certain number of bytes after that header, which represented the "payload" and which was indexed by the last member, the char* member.) Thus, it was a contiguous-block-of-memory struct , with dynamic size. (This would also work in C++ as long as you passed-by-reference, and never by value.)

All instances of a structure or class have the same structure. Luckily, there are some tricks that can be used to 'simulate' what you try to do.

The first trick (which can also be used in C), is to use a union, eg:

struct MyStruct
   {
   int field1;
   char field2;
   int type;
   union
      {
      int field3a;
      char field3b;
      double field3c;
      } field3;
   };

In a union, all members take up the same space in memory. As a programmer you have to be careful. You can only get out of the union what you put in. If you initialize one member of a union, but you read another member, you will probable get garbage (unless you want to do some low-level hacks, but don't do this unless you are very experienced).

Unions often come together with another field (outside the union) that indicates which member is actually used in the union. You could consider this your 'condition'.

A second trick is use the 'state' pattern (see http://en.wikipedia.org/wiki/State_pattern ). From the outside world, the context class looks always the same, but internally, the different states can contain different kinds of information.

A somewhat simplified approach for state is to use simple inheritance, and to use dynamic casts. Depending on your 'condition', use a different subclass, and perform a dynamic cast to get the specific information.

Eg, suppose that we have a Country class. Some countries have a president, others have a king, others have an emperor. You could something like this:

class Country
   {
   ...
   };

class Republic : public Country
   {
   public:
      const string &getPresident() const;
      const string &getVicePresident() const;
   };

class Monarchy : public Country
   {
   public:
      const string &getKing() const;
      const string &getQueen() const;
   };

In your application you could work with pointers to Country, and do a dynamic cast to Republic or Monarchy where the president or king is needed.

This example can be easily transformed into one using the 'state' pattern, but I leave this as an exercise for you.

Personally, I would go for the state pattern. I'm not a big fan of dynamic casts and they always seem to be kind-of-hack for me.

If it's at compile-time, a simple #ifdef or template specialization will serve this purpose just fine. If it's at run-time and you need value semantics, you can use a boost::optional<my_struct_of_optional_members> , and if you're fine with reference semantics, inheritance will solve the problem at hand.

A union and that kind of dirty trick is not necessary.

embed an union into your structure, and use a flag to tell which part of the union is valid.

enum struct_type
{
    cool,
    fine,
    bad
};

struct demo
{
    struct_type type;
    union
    {
        struct
        {
            double cool_factor;
        } cool_part;
        struct
        {
            int fineness;
        } fine_part;
        struct
        {
            char *bad_stuff;
        } bad_part;
    };
    struct
    {
        int life_is_cool;
    } common_part;
};

The pure and simple C++ answer is: use classes.

I can't determine from your question what you are trying to achieve: runtime variation or compile time variation, but either way, I doubt you'll get a workable implementation any other way. (Template metaprogramming aside... which isn't for the faint of heart.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM