Объектная реализация couting с использованием композиции в C++

В более эффективном C++ Мейерс описал способ подсчета экземпляров объектов с помощью базового класса подсчета объектов (пункт 26). Можно ли реализовать тот же метод с использованием композиции, как показано ниже. Есть ли конкретное преимущество использования частного наследования и каковы недостатки использования композиции в этом случае.

PS:- Я повторно использовал код из более эффективного C++ с небольшой модификацией.

    #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_ */

2 ответа

Решение

Этот вопрос связан с

Из этих двух один, вероятно, является дубликатом другого. Но ни один не отвечает на этот вопрос, и я почему-то неохотно отправляю свой ответ одному из них.


Частное наследование может использовать пустую оптимизацию базового класса:

class Printer0
{
    Counted<Printer0> counterObject;
    int m;
};

class Printer1 : Counter<Printer1>
{
    int m;
};

Clang++ и g++ оба говорят sizeof(Printer0) == 8 а также sizeof(Printer1) == 4,

Причина в том, что члены данных должны иметь разные адреса, но один пустой базовый класс не должен использовать память в объекте. Так counterObject один байт большой, и int выравнивается до 4 байт, поэтому Printer0 выглядит так:

  | | XX | | 
  0 1 2 3 4 5 6 7 8 9
          ^ ~~~~~~~~ м
      ^~~~ padding
  ^~~~ counterObject

Композиция вынуждает вас "загрязнять" код вашего класса метаданными (то есть счетчиком), которые не связаны с его основным бизнесом, по моему мнению, делая код менее читабельным для этого случая. Также смотрите ответ @dyp относительно технического аспекта оптимизации пустого класса.

Другие вопросы по тегам