2

Please assume a resource managing class, let's say

template<typename AddressFields>
class AddressBook 
{ 
  std::list<AddressBookEntry<AddressFields> > book; 
};

which holds a list of AddressBookEntry objects. AddressBookEntry basically is supposed to consists of a couple of default member variables plus a customizable fields variable described by the templated AddressFields:

template<typename AddressFields>
struct AddressBookEntry
{
  int id;
  AddressFields fields;
};

I'd like to provide a few basic structures such as

struct Name 
{
  std::string n_first;
  std::string n_last;
};

struct Address
{
  std::string street;
  int zip;
  std::string city;
};

struct Mobile
{
  std::string m_number
};

Now my question is: Is there a way to create new structures based on the existing structures ? I want to allow a user to create his/her own custom AddressFields type by combining, for example, "Name" and "Mobile" to

struct NameMobile
{
  std::string n_first;
  std::string n_last;
  std::string m_number;
};

so it can be plugged into AddressBook. But only with already existing structures.

Steffen
  • 33
  • 4
  • 1
    There's no question here. Are you editing? – John Dibling Apr 27 '12 at 14:50
  • Also, there's no such thing as a "default member variable." Perhas you meant member variables that are default constructed? – John Dibling Apr 27 '12 at 14:50
  • sorry, hit the enter button accidentally ;) – Steffen Apr 27 '12 at 15:10
  • A phone number shouldn't be stored as an int, as there may be leading zeroes. – Lukazoid Apr 27 '12 at 15:22
  • @Lukazoid Thanks for the suggestion. In fact the address book example doesn't have to do anything with my actual problem. It was just the first simple example that came to mind. But for the sake of correctness, I guess string would be more appropriate? – Steffen Apr 27 '12 at 15:45
  • I would use a string yes, was just a minor point in case this was a real implementation :) – Lukazoid Apr 27 '12 at 15:47

2 Answers2

3

There is most certainly. It's called multiple inheritance:

struct NameMobile : Name, Mobile {};

This aggregates Name and Mobile into a new type NameMobile (including all their members, recursively). Since you're declaring it with the struct keyword, the public modifiers (before Name and Mobile) are implied and can thus be omitted.

bitmask
  • 32,434
  • 14
  • 99
  • 159
  • Thanks a lot! Let me think about it for moment. If this solves all my problems and I'll mark it as correct. :) – Steffen Apr 27 '12 at 15:21
  • Make sure you read [this SO answer](http://stackoverflow.com/a/407928/921321) for reasons to avoid MI. However if it does what you require and there are no issues, then go for it – Lukazoid Apr 27 '12 at 15:24
  • @Lukazoid: Yes, I know it's popular to say things that can be easily misused and are often misused are bad. **But under no circumstances should one generalise** (the irony that this statement is a generalisation is not lost on me). – bitmask Apr 27 '12 at 15:29
  • I agree exactly @bitmask, however I do like to be sure that people understand something fully before they implement it blindly. Hence I posted to link to give some more background, to be fair I should have posted a pro-MI answer too, but I think that answer sums it nicely, it's good in a few situations, but lots can be solved without MI. – Lukazoid Apr 27 '12 at 15:33
  • I think this is an abuse of the inheritance mechanism in order to achieve composition. Inheritance reflects an "Is a" relation, which is obviously not the case here (NameMobile is not a Name - it has a name). Use composition instead. – Xyand Apr 27 '12 at 17:52
  • @Albert: Depends on semantics. Of course is a `NameMobile` a `Name`, `NameMobile` is just a terrible name for a type. You are correct, that I'm "abusing" MI for composition, but that is exactly what the OP asked for. It's not our place to tell them their architecture is flawed, because we have never seen their architecture. One more thought; Were you voting down this answer of the problem raised by the question? – bitmask Apr 27 '12 at 18:03
1

Yes. Composition is what I use most frequently:

struct NameMobile
{
  ...
private:
  Name n_name;
  Mobile n_mobile;
};
justin
  • 104,054
  • 14
  • 179
  • 226
  • I was thinking something along the lines. But how do you forward the members? References? – bitmask Apr 27 '12 at 17:46
  • you forward *selectively* ;) specifically, you have many options - choose the one that suits your design best. it depends on many things. some people would use wrapping interfaces, providing accessors, or offering direct access. i'll often use private accessors which validate state, and wrapper methods because i want to expose only part of the interface (or reword) in many cases, or provide additional validation. for accessors, you'd use const-qualified references: `Name& name() { return this->n_name; } \n const Name& name() const { return this->n_name; }` – justin Apr 27 '12 at 18:14