比方说,我想实现一些数学向量类。
为矢量界面会在多个地方被使用:基于阵列矢量,矩阵返回列和行作为矢量接口对象等。
我想重载+, - 运营商为我的向量。每个运营商应该返回一些载体实现类的新构造的对象。
但是,您知道运算符重载应返回一个值或引用。我不能返回一个值,因为我需要运行时多态性,所以我留下引用。但有函数调用对象应在堆上创建后不会死的参考。
所以,我应该如何处理这种情况?
附:我可以创建一个shared_ptr,并返回包含值的引用,但它看起来并不像一个很好的做法。
typedef unsigned int vector_idx_t;
template <class T, vector_idx_t size>
class vector {
public:
virtual ~vector();
virtual T& operator[](const vector_idx_t idx) = 0;
virtual vector<T, size>& operator+ (const T& a) const = 0;
virtual vector<T, size>& operator- (const T& a) const = 0;
virtual vector<T, size>& operator* (const T& a) const = 0;
virtual vector<T, size>& operator/ (const T& a) const = 0;
virtual vector<T, size>& operator+ (const vector<T, size>& vec2) const = 0;
virtual vector<T, size>& operator- (const vector<T, size>& vec2) const = 0;
};
template <class T, vector_idx_t size>
class array_vector: public vector<T, size> {
private:
std::array<T, size> m_elements;
public:
array_vector();
array_vector(std::array<T, size> elements);
array_vector(const vector<T, size>& vec2);
array_vector(std::initializer_list<T> elems);
virtual ~array_vector();
virtual T& operator[](const vector_idx_t idx) {
return m_elements[idx];
}
virtual vector<T, size>& operator+ (const T& a) const {
std::array<T, size> e;
for (vector_idx_t i = 0; i < size; ++i) {
e[i] = m_elements[i] + a;
}
auto v = std::make_shared<array_vector<T, size>>(elems);
return *v;
}
};
我建议稍微修改设计用于容纳实施的多形态性质。
vector
多态性。Data
类包含vector
实施的具体细节。Data
多态性。这将允许您通过值或引用,返回vector
s作为适当的接口。
通过多态性亚型是不能解决所有问题。我明白了什么是你想这样做,但我完全不明白为什么一个多态的模板解决方案是不够的,你需要有虚拟运营商(其中完全不与多态性的亚型拌匀)。
你要能够定义的混合类型的载体操作,这样就可以计算出真正的容器和代理容器之间的结果。
这首先应该要求您有需要,一个代理矩阵列是不是一个真正的容器,而是一个容器的视图,因此将他们两个人应该返回一个真正的容器(基本final类型如:一容器由实际std::array
支持?)。
类似的设计可以通过像管理
template<typename ContainerType, typename ElementType>
class vector_of : public ContainerType
{
public:
vector_of(const ContainerType& container) : ContainerType(container) { }
vector_of<ContainerType, ElementType> operator+(const ElementType& a) const
{
vector_of<ContainerType, ElementType> copy = vector_of<ContainerType,ElementType>(*this);
std::for_each(copy.begin(), copy.end(), [&a](ElementType& element) { element += a; });
}
template<typename T>
vector_of<ContainerType, ElementType> operator+(const vector_of<T, ElementType>& a) const
{
vector_of<ContainerType, ElementType> copy(*this);
auto it = copy.begin();
auto it2 = a.begin();
while (it != copy.end() && it2 != a.end())
{
*it += *it2;
++it;
++it2;
}
return copy;
}
};
这里的技巧是operator +是接受ElementType
元件的一般容器的模板的方法。该代码假定这些类型的容器提供begin
和end
方法,返回一个迭代器(这是在任何情况下,一个聪明的选择,因为它与STL效果很好)。
有了你可以做这样的事情:
class MatrixRowProxy
{
private:
int* data;
size_t length;
public:
MatrixRowProxy(int* data, size_t length) : data(data), length(length) { }
int* begin() const { return data; }
int* end() const { return data + length; }
};
vector_of<std::array<int, 5>, int> base = vector_of<std::array<int, 5>, int>({ 1, 2, 3, 4, 5 });
vector_of<std::vector<int>, int> element = vector_of<std::vector<int>, int>({ 2, 3, 4, 5, 6 });
int* data = new int[5] { 10, 20, 30, 40, 50};
vector_of<MatrixRowProxy, int> proxy = vector_of<MatrixRowProxy, int>(MatrixRowProxy(data, 5));
auto result = base + element + proxy;
for (const auto& t : result)
std::cout << t << std::endl;
所以,你可以添加各种异构的载体,而不需要任何virtual
方法。
当然,这些方法需要建立在方法的新生成的对象。这是通过复制到新vector_of<ContainerType, ElementType>
这件事。没有什么能阻止你从增加第三个模板参数像VectorFactory这需要照顾这个,这样你可以使用它只是包装也是这样运营商的LHS载体。