Как переопределить статическую переменную родительского класса

#c #inheritance #subclass

#c #наследование #подкласс

Вопрос:

Как переопределить статическую переменную родительского класса.

Итак, у меня есть родительский класс

 class DatabaseItem
{
   static int instanceCount;

   DatabaseItem()
   {
     instanceCount  ;
   }
};
  

если у меня есть 2 класса, которые наследуются от DatabaseItem , я хочу, чтобы каждый класс записывал, сколько экземпляров их класса только существует. Как мне это сделать?

Итак:

 class Person : public DatabaseItem
{
  // how do I make sure when I make the call  int numOfpeople = Person::instanceCount;
  // that I only get the number of people objects that exist amp; not all the DatabaseItem
  // objects that exist?
};

class FoodItem : public DatabaseItem
{
  // how do I make sure when I make the call  int numOffoodItems = FoodItem::instanceCount;
  // that I only get the number of FoodItem objects that exist amp; not all the DatabaseItem
  // objects that exist?
};
  

РЕДАКТИРОВАТЬ в ответ на комментарии

Да, но вышесказанное — всего лишь пример, если я сделаю это, то у меня будет много повторяющегося кода…

Итак:

     class DatabaseItem
{
    public:
        static unsigned int instanceCount;
        static Vector <unsigned int> usedIDs;

        unsigned int ID;

        DatabaseItem()
        {
            ID = nextAvailableID();
            usedIDs.add( ID );
            DatabaseItem::instanceCount  ;
        }

        DatabaseItem( unsigned int nID )
        {
            if ( isIDFree( nID ) )
            {
                ID = nID;
            }
            else ID = nextAvailableID();

            usedIDs.add( ID );
            DatabaseItem::instanceCount  ;
        }

        bool isIDFree( unsigned int nID )
        {
            // This is pretty slow to check EVERY element

            for (int i=0; i<usedIDs.size(); i  )
            {
                if (usedIDs[i] == nID)
                {
                    return false;
                }
            }

            return true;
        }

        unsigned int nextAvailableID()
        {
            unsigned int nID = 0;

            while ( true )
            {
                if ( isIDFree( ID ) )
                {
                    return nID;
                }
                else nID  ;
            }
        }
};


class Person    {
    public:
        static unsigned int instanceCount;
        static Vector <unsigned int> usedIDs;

        unsigned int ID;

        Person()
        {
            ID = nextAvailableID();
            usedIDs.add( ID );
            Person::instanceCount  ;
        }

        Person( unsigned int nID )
        {
            if ( isIDFree( nID ) )
            {
                ID = nID;
            }
            else ID = nextAvailableID();

            usedIDs.add( ID );
            Person::instanceCount  ;
        }

        bool isIDFree( unsigned int nID )
        {
            // This is pretty slow to check EVERY element

            for (int i=0; i<usedIDs.size(); i  )
            {
                if (usedIDs[i] == nID)
                {
                    return false;
                }
            }

            return true;
        }

        unsigned int nextAvailableID()
        {
            unsigned int nID = 0;

            while ( true )
            {
                if ( isIDFree( ID ) )
                {
                    return nID;
                }
                else nID  ;
            }
        }
};
  

.. затем я должен переписать тот же код для FoodItem, coffeeRun….

Комментарии:

1. Создайте статическую для каждого производного class..no необходимо переопределить.

2. Вы не переопределяете ее, но вы можете скрыть ее, создав переменную с тем же именем в производном классе.

3. @Tomalak Geret’kal Что, если я сделаю переменные DatbaseItem виртуальными? Итак, виртуальное статическое значение int без знака instanceCount; ? Значит, создатель подкласса ДОЛЖЕН создать такую переменную?

4. @Mack: Члены функции могут быть виртуальными, а не элементами данных.

5. @Tomalak Geret’kal Спасибо за ответ. Есть ли какой-либо другой вариант решения моей проблемы?

Ответ №1:

Используйте шаблоны, чтобы избежать всех подобных проблем с обновлением количества экземпляров в каждом конструкторе и т.д.

 template<class T>
struct Instance
{
  static unsigned int count;
  Instance () { count   ; }
  Instance (const Instanceamp; o) { count   ; }
};
template<class T>
unsigned int Instance<T>::count = 0;
  

Теперь этот шаблон может быть унаследован любым из классов, которые вам нужно подсчитать для их экземпляров:

 class DatabaseItem : public Instance<DatabaseItem> {};
class Person : public DatabaseItem, Instance<Person> {};
class FoodItem : public DatabaseItem, Instance<FoodItem> {};
  

Вот и все!

Всякий раз, когда объявляется объект класса, он выполняет свою работу. Это может быть использовано следующим образом:

 DatabaseItem *pD = new DatabaseItem[5];
Person obj[10];
cout<<Instance<DatabaseItem>::count<<endl;  // 5   10 = 15
cout<<Instance<Person>::count<<endl;        // 10
  

Вам не нужно нигде обновлять count.

Ответ №2:

Я думаю, что невозможно иметь статическую переменную в базовом классе и определять по ней, сколько экземпляров производного класса каждого типа присутствует. Вместо этого в каждом классе должна быть статическая переменная класса, которая увеличивается в конструкторе.

 class Person : public DatabaseItem
{
     static int numPersonItems ;
     Person()
     {
           numPersonItems ;
     }
};

int DatabaseItem::numPersonItems = 0 ;
  

numPersonItems это количество Person экземпляров. Аналогично можно сделать и для FoodItem класса.

Ответ №3:

Учитывая, что вы не можете полагаться на виртуальную отправку в конструкторе базового класса, вам нужно либо предоставить статическую информацию непосредственно ему в качестве параметра, либо предоставить ему производный класс, чтобы он мог запрашивать статическую информацию сам. Последнее проиллюстрировано ниже

 struct Base { 
    //provide whatever actual interface you need your type to have here
    virtual ~Base();
};

template<typename Derived>
struct Intermediate : Base {
    Intermediate() {
        Derived::var  ;  //doesn't rely on polymorphism so ok in constructor
    }
};

struct Derived : Intermediate<Derived> {
    static int var;
};
  

Однако, учитывая ваш конкретный вариант использования, я был бы склонен вообще этого не делать и либо заставить базовый класс распределять уникальные идентификаторы по всем экземплярам, независимо от типа, либо сразу перенести создание идентификатора в отдельный класс / метод и запросить у него уникальный идентификатор:

 template<typename T>
struct UniqueID { 
    static some64bitIntType GetID(); //possibly non-static, lots of ways to handle this
};

struct Object {
    some64bitIntType ID;
    Object() : ID(UniqueID<Object>::GetID()) { }
};
  

Или что-то в этом роде. Лично я был бы склонен не беспокоиться о возврате идентификаторов для повторного использования. Это много дополнительной работы с небольшой практической выгодой, если только вы не пытаетесь ограничить себя относительно небольшим количеством экземпляров.