#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()) { }
};
Или что-то в этом роде. Лично я был бы склонен не беспокоиться о возврате идентификаторов для повторного использования. Это много дополнительной работы с небольшой практической выгодой, если только вы не пытаетесь ограничить себя относительно небольшим количеством экземпляров.