patterncppMinor
Composition or Private Inheritance for Implementing Builder?
Viewed 0 times
builderprivateinheritanceforimplementingcomposition
Problem
Over on StackOverflow, I was asked if I could come up with an example where private inheritance would be preferred to composition (in C++). The following is the situation I described, and I was wondering which implementation you would prefer. Most of the references I've found to private inheritance are poor uses, and I agree that it is rarely useful.
Let's say you have a class
And my original
And the
Now I can create read-only
A similar implementation using composition might look something like this:
```
class Foo
{
public:
Foo(FooData d);
int value() const { return data.value(); }
string somethingElse() const { return data.somethingElse(); }
private:
FooData data;
};
class FooData
{
public:
int value() const { return myValue; }
int somethingElse() const { return mySomethingElse; }
void setValue(int n) { myValue = n; }
void setSomethingElse(string s) { myS
Let's say you have a class
Foo that should be immutable, but it's rather complicated to set up (maybe you're reading settings from a file), so you decide to create a separate class FooBuilder to set up your Foo objects for you. My solution (using private inheritance) is to declare an abstract interface:class MutableFoo
{
public:
virtual void setValue(int n) = 0;
virtual void setSomethingElse(string s) = 0;
};And my original
Foo class:class Foo : private MutableFoo
{
public:
Foo(FooBuilder builder)
{
builder.build(this);
}
int value() const { return myValue; }
string somethingElse() const { return mySomethingElse; }
private:
void setValue(int n) { myValue = n; }
void setSomethingElse(string s) { mySomethingElse = s; }
int myValue;
string mySomethingElse;
};And the
FooBuilder:class FooBuilder
{
public:
FooBuilder(string fileWithSettings);
void build(MutableFoo *fooToBuild);
};Now I can create read-only
Foo objects without declaring them all to be const:Foo aFoo(FooBuilder(aFileWithSettings));A similar implementation using composition might look something like this:
```
class Foo
{
public:
Foo(FooData d);
int value() const { return data.value(); }
string somethingElse() const { return data.somethingElse(); }
private:
FooData data;
};
class FooData
{
public:
int value() const { return myValue; }
int somethingElse() const { return mySomethingElse; }
void setValue(int n) { myValue = n; }
void setSomethingElse(string s) { myS
Solution
Herb Sutter in his book 'Exceptional C++', Item 24 (Uses and Abuses of Inheritance), discusses the issue, and cites the following reasons for using private inheritance (instead of containment):
If one of these situations applies, then you must use private inheritance. Otherwise, containment is preferred.
The last of these reasons is cited as a possible reason for protected inheritance.
He also comments:
That's as complete a list as I can make of the reasons to use non-public inheritance. (In fact, just one additional point would make this a complete list of all reasons to use any kind of inheritance: We need public inheritance to express IS-A. [...])
The item occupies 8 pages.
- Override a virtual function
- Access to a protected member
- Construct the used object before, or destroy it after, another base sub-object
- Share a common virtual base class or override the construction of a virtual base class
- We benefit substantially from the empty base class optimization
- We need "controlled polymorphism" - LSP IS-A, but in certain code only
If one of these situations applies, then you must use private inheritance. Otherwise, containment is preferred.
The last of these reasons is cited as a possible reason for protected inheritance.
He also comments:
That's as complete a list as I can make of the reasons to use non-public inheritance. (In fact, just one additional point would make this a complete list of all reasons to use any kind of inheritance: We need public inheritance to express IS-A. [...])
The item occupies 8 pages.
Context
StackExchange Code Review Q#2268, answer score: 3
Revisions (0)
No revisions yet.