c++compositionprivate-inheritance

Object Instantiations couting using composition in c++


In More effective C++ Meyers has described a way to count the instantiation of the objects using an object counting base class (item 26). Is it possible to implement the same using composition technique as below . Is there a specific advantage using private inheritance and what are the drawbacks of using composition in this case.

ps:- I have reused the code from More effective C++ with small modification.

    #ifndef COUNTERTEMPLATE_HPP_
    #define COUNTERTEMPLATE_HPP_
    #include <iostream>
    #include <stdio.h>
    #include <stdlib.h>

    template <class BeingCounted>
    class Counted {
    public:
        static int ObjectCount(){return numOfObjects;}
        Counted();
        Counted(const Counted& rhs);
        ~Counted(){--numOfObjects;}
    protected:
    private:
        static int numOfObjects;
        static int maxNumOfObjects;
        void init();
    };

    template<class BeingCounted> Counted<BeingCounted>::Counted()
    {
        init();
    }

    template<class BeingCounted> Counted<BeingCounted>::Counted(const Counted& rhs)
    {
        init();
    }

    template<class BeingCounted> void Counted<BeingCounted>::init()
    {
        if(numOfObjects>maxNumOfObjects){}
        ++numOfObjects;
    }

    class Printer
    {
            public:
        static Printer* makePrinter(){return new Printer;};
        static Printer* makePrinter(const Printer& rhs);
        Counted<Printer>& getCounterObject(){return counterObject;}
        ~Printer();
            private:
        Printer(){};
        Counted<Printer> counterObject;
        Printer(const Printer& rhs){};
    };

    #endif /* COUNTERTEMPLATE_HPP_ */


Solution

  • This question is related to

    Of those two, one is probably a duplicate of the other. But neither answers this question, and I'm somehow reluctant to post my answer to one of them.


    Private inheritance can make use of the empty base class optimization:

    class Printer0
    {
        Counted<Printer0> counterObject;
        int m;
    };
    
    class Printer1 : Counter<Printer1>
    {
        int m;
    };
    

    Clang++ and g++ both say sizeof(Printer0) == 8 and sizeof(Printer1) == 4.

    The reason is that data members have to have different addresses, but a single empty base class does not need to use up memory in the object. So counterObject is one byte large, and int is aligned to 4 byte, therefore Printer0 looks like this:

      | | X X |       | 
      0 1 2 3 4 5 6 7 8 9
              ^~~~~~~~~ m
          ^~~~ padding
      ^~~~ counterObject