Let's say we have two classes, A
and B
. When using composition to model a "has-a" or "is-implemented-in-terms-of" relationship (e.g. B
has-a A
), one of the drawbacks vs. inheritance is that B
does not the contain public functionality of A
that it requires. In order to gain access to A
s public functions, it is necessary to provide forwarding functions (as opposed to inheritance, where B
would inherit all of A
s public functions).
To give a more concrete example, let's say we have a Person
which has-a ContactInfo
:
using namespace std;
class ContactInfo
{
public:
ContactInfo();
void updateAddress(string address);
void updatePhone(string phone);
void updateEmail(string email);
private:
string address;
string phone;
string email;
};
class Person
{
public:
Person();
// Forwarding functions:
void updateAddress(string address){contactInfo.updateAddress(address)};
void updatePhone(string phone){contactInfo.updatePhone(phone)};
void updateEmail(string email){contactInfo.updateEmail(email)};
private:
ContactInfo contactInfo;
};
Ignoring any deficiencies in the design (it is just a contrived example to demonstrate my question below), I have had to tediously replicate the exact function signatures from ContactInfo
in Person
. In a more complex example there could be many such functions, and many layers of composed classes, leading to much code duplication with all the usual problems of maintenance and being error-prone, etc.
Nonetheless, this is the recommended practice for modelling "has-a" or "is-implemented-in-terms-of" according to sources such as Item 38 of Meyers' Effective C++, and Item 24 of Sutter's Exceptional C++ (link).
Whilst researching this, I came across this Wikipedia article which discusses the same topic. At the bottom of the article, it suggests the following:
One drawback to using composition in place of inheritance is that all of the methods being provided by the composed classes must be implemented in the derived class, even if they are only forwarding methods. [...] This drawback can be avoided by using traits.
I am fairly new to the concept of traits and with everything I have read, I am finding it hard to relate to the above statement. My question therefore is: How would one go about using traits to avoid forwarding functions with composition? An answer based on my example (Person
and ContactInfo
) would be ideal.
EDIT: Just to clarify, in response to some of the answers, I am aware of private inheritance as an alternative to composition for modelling "is-implemented-in-terms-of". My question is not about that, it is specifically about the meaning of Wikipedia's statement relating to traits. I am not asking for alternatives to composition. I've bolded my question to make it clearer that this is what I'm asking.
The article talk about inheritance with Interface,
so in fact it tells that the object have to respect some signatures.
type traits can be used to check if signature is correct and dispatch to appropriate function
For example some STL algorithms wait for type Iterator, but those iterators don't inherit from a
class Iterator
but must provide some contract (operator ++()
,operator !=(rhs)
,operator*()
).with the article example:
And code:
First of all I should mention that traits are different things in C++/STL and languages like PHP, Lasso etc. It looks like the article from wikipedia refers to PHP-like traits because C++/STL traits are not designed for polymorphic reuse (we are speaking about code reuse with polymorphic behavior, right?). They designed to simplify declaration of template classes.
Traits are used in some languages that don't support multiple inheritance (PHP, Lasso etc). Traits allow to "emulate" multiple inheritance (but multiple inheritance and traits are not exactly the same).
In contrast C++ doesn't support PHP-traits but supports multiple inheritance. So if speaking about C++ then trait-like solution will be something like this:
So to answer your question
1) Traits don't avoid forwarding functions with composition because traits work independently from composition. (The article from Wikipadia is misleading a little regarding the relationship between traits and composition)
2) PHP/Lasso-like traits can be partially emulated in C++ with multiple inheritance.
AFAIK a trait class is something like the following:
That is: a compile-time templated class where you can implement (and/or specialize it) your delegate methods in order to forward whatever you need without (for whatever reason you have) recurring to inheritance.
http://en.wikipedia.org/wiki/Trait_(computer_programming)
Maybe you can try private inheritance:
Although you may want to watch out for the caveats listed in this FAQ:
Otherwise the example of composition provided seems identical to yours. Clicking on the traits link in the wikipedia article didn't provide any C++ articles, and the link in the references seems to be about
type traits
. I couldn't find howtype traits
has anything to do with your scenario.