Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ policy based design: Inheritance vs composition

At Meeting C++ 2019, Jon Kalb gave a talk about template techniques and mentioned policy classes. See here for the source: https://youtu.be/MLV4IVc4SwI?t=1815

The interesting code snippet in question is:

template<class T, class CheckingPolicy>
struct MyContainer : private CheckingPolicy
{
    ...
}

I've seen this type of design quite often and I was wondering if inheritance here has any real advantages over composition. In my personal experience I've heard much about the Prefer composition over inheritance paradigm. So the way I would have written the code would be more like this:

template<class T, class CheckingPolicy>
struct MyContainer
{
    CheckingPolicy policy;
    ...
}

There wouldn't be any virtual functions involved. Nevertheless I'd appreciate it if you could share some insights how these differ. I would be especially interested in differences in memory layout and its implications. Would it make a difference if CheckingPolicy has no data members, but only a check method or an overloaded call operator?

like image 670
flowit Avatar asked Dec 27 '19 15:12

flowit


People also ask

Which design inheritance or composition is better?

Composition offers better test-ability of a class than Inheritance. If one class consists of another class, you can easily construct a Mock Object representing a composed class for the sake of testing.

How is inheritance different from composition?

Inheritance and composition are two programming techniques developers use to establish relationships between classes and objects. Whereas inheritance derives one class from another, composition defines a class as the sum of its parts.

Is inheritance better than composition C#?

One of the major advantages of inheritance is that we implicitly get all the base class methods in the derived class and there is no extra performance cost of invocation. On the contrary, with composition, we are creating a composite object by plugging in the component objects.

Is composition and inheritance same?

Composition is in contrast to inheritance, it enables the creation of complex types by combining objects (components) of other types, rather than inheriting from a base or parent class. To put it simply, composition contains instances of other classes that implement the desired functionality.


1 Answers

One possible reason: when you inherit from CheckingPolicy, you can benefit from empty base class optimization.

If CheckingPolicy is empty (i.e. it has no non-static data members other than bit-fields of size 0, no virtual functions, no virtual base classes, and no non-empty base classes), it will not contribute to the size of MyContainer.

In contrast, when it is a data member of MyContainer, even if CheckingPolicy is empty, size of MyContainer will be increased by at least one byte. At least, because due to alignment requirements you could have additional padding bytes.

This is the reason why, e.g., in the implementation of std::vector you can find ihnehritance from an allocator. For example, libstdc++'s implementation:

template<typename _Tp, typename _Alloc>
struct _Vector_base {
    typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template
        rebind<_Tp>::other _Tp_alloc_type;

    struct _Vector_impl : public _Tp_alloc_type, public _Vector_impl_data { 
        // ...
    };

    // ...
};

Stateless allocators (like CheckingPolicy with no non-static data members) will not contribute into std::vector's size.

In C++20 we'll have [[no_unique_address]] to potentially address this issue: whereas empty base optimization is required for standard layout types, [[no_unique_address]] is just a permission, not a requirement. (Thanks Nicol Bolas for pointing that out.)

like image 123
Evg Avatar answered Nov 15 '22 00:11

Evg