У меня есть следующие классы материалов, которые будут использоваться классом BlockTest. Сам класс Material никогда не будет использоваться и служит только для предоставления интерфейса для реализации всеми дочерними классами. Следовательно, класс Material потенциально может быть абстрактным классом.
class Material {
public:
Material() : m_nQuantity(0) {}
Material(uint8_t amount) : m_nQuantity(amount) {}
virtual ~Material() {}
virtual Vector2D* getTextureTop() {
static Vector2D vector(0.0f, 0.0f);
return &vector;
}
virtual uint16_t getMaterialId() {
return 0;
}
uint8_t getQuantity() {
return m_nQuantity;
}
uint8_t m_nQuantity;
};
class GrassMaterial : public Material {
public:
GrassMaterial () : m_nQuantity(0) {}
GrassMaterial (uint8_t amount) : Material(amount) {}
virtual ~GrassMaterial () {}
virtual Vector2D* getTextureTop() {
static Vector2D vector(0.5f, 0.5f);
return &vector;
}
virtual uint16_t getMaterialId() {
return GRASS_BLOCK_ID;
}
uint8_t getQuantity() {
return m_nQuantity;
}
};
Класс Block должен иметь ссылку на до 4 различных дочерних классов Material, которые будут разными для каждого экземпляра класса Block.
class BlockTest {
public:
void render() {
std::cout << "BlockTest(Material&& m1, Material&& m2)" << std::endl;
std::cout << m_m[0].getTextureTop()->m_x << ":" << m_m[0].getTextureTop()->m_y << std::endl;
std::cout << (int)m_m[0].getQuantity() << std::endl;
std::cout << m_m[1].getTextureTop()->m_x << ":" << m_m[1].getTextureTop()->m_y << std::endl;
std::cout << (int)m_m[1].getQuantity() << std::endl;
}
BlockTest() {}
BlockTest(const BlockTest &obj) = delete;
~BlockTest() {
m_m[0].m_nQuantity = 255;
m_m[1].m_nQuantity = 255;
}
Material m_m[4];
};
Использование:
BlockTest* bt = new BlockTest();
Material* m1 = new (&(b1->m_m[0])) GrassMaterial(54);
Material* m2 = new (&(b1->m_m[0])) StoneMaterial(84);
Выше я нашел один из способов достижения желаемого поведения, однако он выглядит как действительно очень плохой код, также я не уверен, какова производительность Оператор размещения нового размещения сравнивается с распределением стека.
Производительность имеет решающее значение, поскольку я могу создавать ~ 840 миллионов объектов BlockTest в течение примерно 10 секунд, поэтому я не могу просто иметь массив Material * для каждого класса и конструирование каждого материала с помощью оператора new.
Объекты BlockTest имеют память, предварительно выделенную фрагментами по 65 536, а затем конструируются с использованием оператора размещения new для минимизации затрат на выделение кучи, и это не вызывает никаких проблем с производительностью. .
Что мне действительно нужно
Дочерние классы Материала определяют постоянные данные, которые различаются для каждого типа Материала (по сути, UV-карты текстуры, MATERIAL_ID, и т. д. c), поэтому эти переменные могут быть c статичными и просто доступны с помощью методов stati c без необходимости создавать экземпляр без дополнительных затрат памяти. Однако для каждого класса BlockTest также необходимо связать каждый дочерний класс Material, из которого он состоит (от 1 до 4 различных материалов), с количеством.
Например: BlockTest * b1 состоит из 3 материалов.
- GrassMaterial в количестве 50.
- StoneMaterial в количестве 155.
- IronMaterial в количестве 50.
BlockTest * b2 состоит из 2 материалов.
- GrassMaterial с количеством 90.
- SandMaterial с количеством 165.
Для каждого экземпляра BlockTest это потребуется доступ к методам stati c каждого содержащегося в нем Материала (методы всегда одинаковы и определены в базовом классе материала), и ему потребуется способ связать каждый из этих материалов с его количеством.
I Представьте, что шаблоны могут быть лучшим способом приблизиться к этому, однако я не уверен, как подойти к связыванию каждого класса шаблона с количеством. Также, если класс BlockTest является шаблоном, мне нужен способ хранения массива объектов BlockTest * со всеми различными аргументами шаблона.