Я пытаюсь создать шаблонные классы для матриц и векторов разных размеров.Для моего класса Vector я перегружал операторы + = и +, чтобы иметь возможность добавлять два вектора одинаковой длины.Если длины не совпадают, я хочу, чтобы компилятор выдавал ошибку.Я хочу хранить несколько таких объектов mvc :: Vector (с разными длинами) внутри std :: vector.Для этого я создал базовый класс mvc :: VectorBase, от которого я наследую все объекты mvc :: Vector.Теперь я могу написать
std::vector<std::unique_ptr<mvc::VectorBase>> vectorBuffer;
Чтобы иметь возможность вызывать функции-члены MyVector из vectorBuffer, я добавил чисто виртуальные функции для этих членов, чтобы я мог использовать
vectorBuffer[0]->GetLength().
Моя проблема: яне может написать код, например, потому что VectorBase не знает перегрузки оператора.
mvc::Vector<2> result = (*vectorBuffer[0]) + (*vectorBuffer[1]);
Попытка добавить перегрузку оператора как чисто виртуальную в mvc :: VectorBase не сработала, потому что один аргумент должен быть аргументом шаблонаиз класса шаблонов mvc :: Vector, который я не могу использовать вне шаблона.
#include <vector>
#include <memory>
#define T float
namespace mvc
{
class VectorBase
{
public:
// virtual Vector operator+= (Vector<Tlength>& other) = 0;
virtual int GetLength() const = 0;
};
template<int Tlength>
class Vector : public VectorBase
{
private:
T vec[Tlength];
public:
Vector operator+ (Vector<Tlength>& other)
{
for (int i = 0; i < Tlength; i++)
{
vec[i] += other.vec[i];
}
return *this;
}
int GetLength() const
{
return Tlength
}
}
}
int main()
{
mvc::Vector<3> vec3_1;
mvc::Vector<3> vec3_2;
mvc::Vector<4> vec4_1;
mvc::Vector<3> result = vec3_1 + vec3_2; // this line works properly
mvc::Vector<3> result = vec3_1 + vec4_1; //this line won´t compile (as expected)
std::vector<std::unique_ptr<mvc::VectorBase>> vectorBuffer;
vectorBuffer.push_back(std::make_unique<mvc::Vector<2>>());
vectorBuffer.push_back(std::make_unique<mvc::Vector<2>>());
mvc::Vector<2> result = (*vectorBuffer[0]) + (*vectorBuffer[1]); // <-- this is what i want to be able to do
}
Как реализовать желаемое поведение: vectorBuffer [0] + vectorBuffer [1] работает ТОЛЬКО, если объекты MyVectorсгенерированный с тем же шаблоном (длина равна)
Это уже работает с двумя отдельно сохраненными экземплярами MyVector.Сбой, когда я использую полиморфизм для хранения нескольких объектов mvc :: Vector в одном и том же std :: vector.
EDIT: Перегрузив оператор + с базовым классом в качестве возвращаемого типа, я получилзапрашиваемое поведение: оператор
#include <vector>
#include <memory>
#include <iostream>
#define T float
namespace mvc
{
class VectorBase
{
public:
virtual VectorBase* operator+ (VectorBase& other) = 0;
virtual int GetLength() const = 0;
virtual T GetElem(int i) const = 0;
virtual void Print() const = 0;
};
template<int Tlength>
class Vector : public VectorBase
{
private:
T vec[Tlength];
public:
Vector(T initValue)
{
for (int i = 0; i < Tlength; i++)
{
vec[i] = initValue;
}
}
VectorBase* operator+ (VectorBase& other) override
{
if (other.GetLength() != Tlength)
{
std::cout << "[Error]: Argument dimensions mismatch. Program will terminate." << std::endl;
std::cin.get();
exit(-1);
}
//Vector<Tlength> tmpOther = dynamic_cast<Vector<Tlength>&>(other);
for (int i = 0; i < Tlength; i++)
{
//vec[i] += tmpOther.vec[i];
vec[i] += other.GetElem(i);
}
return this;
}
Vector<Tlength> operator+ (Vector<Tlength>& other)
{
for (int i = 0; i < Tlength; i++)
{
vec[i] += other.GetElem(i);
}
return *this;
}
int GetLength() const override
{
return Tlength;
}
T GetElem(int i) const override
{
return vec[i];
}
void Print() const override
{
for (int i = 0; i < Tlength; i++)
{
std::cout << " " << vec[i] << "\n";
}
std::cout << std::endl;
}
};
}
int main()
{
/* without polymorphism */
// vector1
mvc::Vector<2> vec3_1 = mvc::Vector<2>(1.2f);
vec3_1.Print();
// vector2
mvc::Vector<2> vec3_2 = mvc::Vector<2>(3.4f);
vec3_2.Print();
// vector2 = vector1 + vector2
vec3_2 = vec3_1 + vec3_2;
vec3_2.Print();
/* with polymorphism */
// vector buffer storing base class objects
std::vector<mvc::VectorBase*> vectorBuffer;
//vector1
vectorBuffer.push_back(new mvc::Vector<3>(3.5f));
vectorBuffer[0]->Print();
//vector2
vectorBuffer.push_back(new mvc::Vector<3>(2.8f));
vectorBuffer[1]->Print();
//vector2 = vector1 + vector2
vectorBuffer[1] = *vectorBuffer[0] + *vectorBuffer[1];
vectorBuffer[1]->Print();
std::cin.get();
for (unsigned int i = 0; i < vectorBuffer.size(); i++)
{
delete vectorBuffer[i];
}
}
plus дважды перегружен, что также поддерживает «неполиморфное» использование.(см. пример внутри main)
Внутри оператора + переопределение является комментарием, использующим решение @Vikas Awadhiya dynamic_cast.Это тоже работает.В настоящее время я не знаю о производительности по сравнению с моим текущим решением с функцией виртуального геттера GetElem.
Пока мне удалось заставить его работать только с необработанными указателями.Все еще работаем над решением unique_ptr.
Спасибо за все ответы!