Не вижу красивого решения, подходящего под Ваши ограничения. Мне кажется, можно добавить дополнительную абстракцию: BaseObject <- BasePoint <- Point, а в GameField из LevelLoader передавать не массив BaseObject'ов, а контейнер (назовем его Level, например), который содержит Ваши точки и прочие игровые объекты в отдельных структурах данных.
С другой стороны, если у Вас GameField - это доска для игры в ГО, на которой всего-то и есть, что черные точки да белые точки, тогда вовсе нет смысла создавать BaseObject. Задача больше похожа на архитектурную, чем на техническую, и решать ее будет удобнее, если Вы подробнее опишете задумку.
UPD. p. s. От "грязных" трюков совсем уж отказываться не стоит, особенно если приперло. В Qt, например, реализован механизм определения типа, и это не костыль, а жизненно важная фича для реализации концепции управления объектами. А в Java так и вовсе существует т. н. "рефлексия", что подразумевает не только способ определить имя класса, но и получить информацию о его методах и атрибутах. Казалось бы, какая гадость! Но ведь работает.
UPD2: Не знаю, актуально это еще для Вас или нет, но я наткнулся вот на какой трюк в Книге "Эккель - Философия C++, часть вторая", страница 234.
template <class t>
class base {
static int sn_objects;
public:
base() {
sn_objects++;
}
~base() {
sn_objects--;
}
static int count() {
return sn_objects;
}
};
template<class t> int base<t>::sn_objects = 0;
class daughter : public base<daughter> {};
class son : public base<son> {};
int main(int argc, char** argv) {
daughter d1;
daughter d2;
daughter d3;
son s1;
std::cout << daughter::count() << std::endl; // --------- 3 ---------
std::cout << son::count() << std::endl; <b> // --------- 1 ---------
return 0;
}
Однако в этом случае мы не сможем посчитать все объекты, унаследованные от
base. Только если мы base унаследуем от какого-нибудь другого класса, где будем считать статические переменные по-старинке:
#include <iostream>
class the_very_base {
static int sn_common_counter;
public:
the_very_base() {
sn_common_counter++;
}
~the_very_base() {
sn_common_counter--;
}
static int count_all() {
return sn_common_counter;
}
};
int the_very_base::sn_common_counter = 0;
template <class t>
class base : public the_very_base {
static int sn_objects;
public:
base() {
sn_objects++;
}
~base() {
sn_objects--;
}
static int count() {
return sn_objects;
}
};
template<class t> int base<t>::sn_objects = 0;
class daughter : public base<daughter> {};
class son : public base<son> {};
int main(int argc, char** argv) {
daughter d1;
daughter d2;
daughter d3;
son s1;
std::cout << daughter::count() << std::endl; // --------- 3 ---------
std::cout << son::count() << std::endl; // --------- 1 ---------
std::cout << the_very_base::count_all() << std::endl; // --------- 4 ---------
return 0;
}
Основано, разумеется, на статических переменных, но только в самом исходном коде статическая переменная всего одна - не приходится объявлять их по 10 штук.