我想设计一个类PrimitiveType
,它用作数学实体的抽象类,例如标量,向量,张量等,以将它们存储在std::vector<PrimitiveType *> myVector
中,我可以通过它进行迭代。例如,有两个相同大小的矢量,比如myVector1
和myVector2
,我希望能够做类似的事情
for (size_t i = 0; i < myVector1.size(); i++)
myVector1[i] += myVector2[i];
并且不想关心我是否添加了标量,向量或张量。到目前为止,我想出了
#include <algorithm>
#include <cstddef>
#include <iostream>
template<class T> class Scalar;
template<class T>
class PrimitiveType
{
protected:
size_t size_;
T *value_;
public:
virtual ~PrimitiveType() = 0;
PrimitiveType & operator+=(const PrimitiveType &primitiveType)
{
for (size_t i = 0; i < size_; i++)
value_[i] += primitiveType.value_[i];
return *this;
}
};
template<class T> PrimitiveType<T>::~PrimitiveType() {};
template<class T>
class Scalar : public PrimitiveType<T>
{
using PrimitiveType<T>::size_;
using PrimitiveType<T>::value_;
public:
Scalar(T value = 0.0)
{
size_ = 1;
value_ = new T(value);
}
~Scalar() { delete value_; }
operator T &() { return *value_; }
};
template<class T>
class Vector : public PrimitiveType<T>
{
using PrimitiveType<T>::size_;
using PrimitiveType<T>::value_;
public:
Vector(T value = 0.0)
{
size_ = 3;
value_ = new T[size_];
std::fill(value_, size_, value);
}
~Vector() { delete[] value_; }
T & operator()(size_t index) { return value_[index]; }
};
int main()
{
Scalar<double> s(3.2);
std::cout << s << std::endl;
static const size_t size = 3;
std::vector<PrimitiveType<double> *> p = std::vector<PrimitiveType<double> *>(size);
for (size_t i = 0; i < size; i++)
{
p[i] = new Scalar<double>();
*(p[i]) += s;
std::cout << *static_cast<Scalar<double> *>(p[i]) << std::endl;
}
}
但我不认为这是一个非常干净的解决方案。特别是,
1)我希望能够在子类中使用初始化列表,但是会遇到依赖名称查找的问题,例如
错误:'使用PrimitiveType :: size_'不是'Scalar'的非静态数据成员
如何实现Scalar(T value = 0.0) : size_(1) , value_(new T(value)) {}
之类的内容?
2)我实际上更愿意将value_
设为静态数组,因为我在编译时知道value_
对Scalar
,Vector
的大小{...}当然,这不适用于PrimitiveType
,但是,永远不会创建PrimitiveType
的实例。
答案 0 :(得分:2)
编辑:完成编辑,因为其他解决方案无效。
嗯,问题的最简单方法是将存储从主类移动到基类并提供元素的访问器:
template <class C>
class PrimitiveType {
public:
PrimitiveType & operator+=(const PrimitiveType &primitiveType) {
if (this->_size() != primitiveType._size()) {
throw "Incompatible type." ;
}
for (size_t i = 0 ; i < this->_size() ; ++i) {
this->_get(i) += primitiveType._get(i) ;
}
return *this ;
}
protected:
virtual C& _get (size_t) = 0 ;
virtual C _get(size_t) const = 0 ;
virtual size_t _size () const = 0 ;
};
然后在Scalar
和Vector
例如:
template <class C>
class Scalar : PrimitiveType <C> {
C _value ;
public:
Scalar (C const& c) : _value(c) { }
protected:
virtual C& _get (size_t) = 0 { return _value ; }
virtual C _get(size_t) const = 0 { return _value ; }
virtual size_t _size () const = 0 { return 1 ; }
};
template <class C, int N = 3>
class Vector : PrimitiveType <C> {
std::array <C, N> _values ;
public:
Scalar (std::initializer_list <C> l) : _values(l) { }
protected:
virtual C& _get (size_t i) = 0 { return _values(i) ; }
virtual C _get(size_t i) const = 0 { return _values(i) ; }
virtual size_t _size () const = 0 { return _values.size() ; }
};
编辑结束。
关于第一个问题,只需在PrimitiveType中添加一个受保护的构造函数,然后从子类中调用它:
class PrimitiveType {
protected:
PrimitiveType (/* */) : _values(/* */), /* ... */ { }
};
class Scalar {
public:
Scalar (/* */) : PrimitiveType(/* */) { }
}
对于第二个问题,添加存储类型作为基本类型的第二个参数模板:
template <class C, class S = std::vector <C>>
class PrimitiveType { /* */ }
template <class C>
class Scalar : public PrimitiveType <C, std::array <C, 1>> { /* */ }
详细示例:
template <class C, class S = std::vector <C>>
class PrimitiveType {
public:
PrimitiveType & operator+=(const PrimitiveType &primitiveType) {
/** Same code as yours. **/
}
protected:
S _values ;
PrimitiveType (std::initializer_list <C> l) : _values(l) { }
};
template <class C>
class Scalar : public PrimitiveType <C, std::array <C, 1>> {
public:
Scalar (C const& c) : PrimitiveType({c}) { }
};