飞行器实时仿真算法研究本科毕业论文(编辑修改稿)内容摘要:

部肯定会有一个指向向量结构体的指针,那么这个指针该是什么属性。 const or nonconst ,鬼知道。 这时候通过一个视图类和大量的 const 属性来使代码正常工作是件非常困难的事,无法预料什么时候会发生错误,而且编码时代码混乱不堪,这不是我想要 本科毕业设计论文 8 的。 所以仅有两个类是不够的 ,事实上需要 5 个类来实现需求分析中的功能。 GneVector 一般矩 阵类, AlmostVector 类, ConstVectorView 常视图类,VectorView 类和 Vector 向量类,它们之间的继承关系如下: 图 31 继承关系图 根据类的抽象设计原则,最底层的类应该具有最通用的方法和数据,若需要使用未知的方法,可将此方法声明为虚函数,留给派生类取定义。 从上面的构架图中可知, GneVector 类为最底层 基类 , 应该具有最通用的方法和数据。 由于视图类也是继承于 GneVector,所以 GneVector 类不应该包涵数据,但是要用到有些方法要用到向量元素,所以可以通过虚函 数来取得派生类的数据。 GneVector 接口 根据以上的分析就可以写出 GneVector 类的接口 //基类 template typename T class GneVector { public: //constructor GneVector(); virtual ~GneVector(); 本科毕业设计论文 9 //三个类都要重写的方法 virtual const sliceamp。 getSlice() const = 0。 virtual const valarrayTamp。 constVal() const = 0。 //三个类公有的方法 size_t size() const { return getSlice().size()。 } size_t start() const { return getSlice().start()。 } size_t stride() const { return getSlice().stride()。 } size_t index(size_t i) const { return getSlice().start() + i*getSlice().stride()。 }。 .................... }。 以上代码省略了很多函数和其具体实现,注意到所有的成员函数都是 const属性函数,这是因为这些方法都是对 Vector、 VectorView、和 ConstVectorView类进行泛化得出的共有方法,至于其他的方法应该根据特点归入某个类,然后具体实现。 ConstVectorView 接口 由于 ConstVectorView 继承于基类,有些方法已经在基类中实现,所以该类本身比较简单,提供构造函数,视图函数,和元素存取功能即可。 template typename T class ConstVectorView : public GneVectorT //常视图 { private: const valarrayT* pVectorData_。 slice viewSlice_。 public: //重写基类的虚函数 virtual const sliceamp。 getSlice() const。 virtual const valarrayTamp。 constVal() const。 //以下两个构造函数是为了 //Vector ConstVectorView //VectorView ConstVectorView //ConstVectorView ConstVectorView ConstVectorView(const GneVectorT amp。 vec)。 ConstVectorView(const GneVectorT amp。 vec, const sliceamp。 s)。 本科毕业设计论文 10 ................. T operator [](size_t i) const { return cref(i)。 } T operator ()(size_t i) const { return cref(i)。 } }。 // end of class ConstVectorViewT AlmostVector 接口 AlmostVector 类的存在时为了对 Vector 类和 VectorView 类解耦,也可以大幅度提高代码的复用率。 接口大 致如下: //VectorView and Vector should inherit this class template typename T class AlmostVector : public GneVectorT { public: AlmostVector()。 virtual ~AlmostVector()。 //override this function in VectorView and Vector virtual valarrayTamp。 val() = 0。 //VectorView and Vector 的共有函数 //subVector ConstVectorViewT subVector(const slice amp。 s) const。 … }。 Vector 接口 由于前面的设计比较合理,现在对 Vector 类编码时非常简单,很多方法已经通过两个基类实现过了。 但是注意 Vector 类包含向量元素 , 并且提供尽可能多的构造函数,以便使用能使不同的数据类型转为 Vector 类型。 接口大致如下: //向量类 template typename T class Vector : public AlmostVectorT { private: //保存向量元素 valarrayT vectorData_。 本科毕业设计论文 11 slice slice_。 public: //重写基类的虚函数 virtual const sliceamp。 getSlice() const。 virtual const valarrayTamp。 constVal() const。 //由 STL valarray 构造 Vector(const valarrayTamp。 val)。 Vector(const valarrayTamp。 val, const sliceamp。 s)。 ................................ Vector(const T * p, size_t n)。 //以下两个构造函数是为了 //Vector Vector //VectorView Vector //ConstVectorView Vector Vector(const GneVectorT amp。 vec)。 Vector(const GneVectorT amp。 vec, const slice amp。 s)。 … }。 VectorView 接口 template typename T class VectorView : public AlmostVectorT //可变视图 { private: valarrayT* pVectorData_。 slice viewSlice_。 public: //重写基类的虚函数 virtual const sliceamp。 getSlice() const。 virtual const valarrayTamp。 constVal() const。 //下面两个构造函数是为了 //Vector MatrixView //VectorView VectorView VectorView(AlmostVectorT amp。 vec)。 本科毕业设计论文 12 .................... virtual valarrayTamp。 val()。 …… . }。 补充说明 上面接口中使用到的 slice 类型是 C++标准库中 valarray 类的组成部分,大致结构如下 : class slice { public: ................... protected: size_t _Start, _Len, _Stride。 }。 可以看到 slice 类主要保存三个数据,即 1. 向量的第一个元素的下标, _Start 2. 向量的长度, _Len 3. 步长,即每个元素之间 的间隔, _Stride 这种类型可以完全使用到我们的视图类中,这也是为什么选择 valarray 模板作为内置向量类型的原因之一。 上面对接口的陈述中没有提到 Vector 类型的输入和输出,这里作已简要说明。 由于输出只需要对对象具有只读权限即可,而输入则要求对对象的读写权限。 所以输出可以放到 GneVector 底层基类中,作为所有派生类的共有函数。 而输入则需放到 AlmostVector 类中,作为 Vector 和 VectorView 类的共有函数。 决定某个函数放在基类还是派生类需要很周全的考虑,基类和派生类可以比作一个 杠杆,不能一头很重,一头很轻,代码失衡会导致后期的编码和维护非常困难。 输入输出函数的声明如下: friend std::ostreamamp。 operator ( std::ostream amp。 os, const GneVectorT amp。 avec)。 friend std::istreamamp。 operator ( std::istream amp。 is, AlmostVectorT amp。 avec)。 最后介绍本类初始化时的一个特点。 初始化一个向量对象有很多种方法,最直接的方法是给每一个元素赋值,如下: for(size_t i=0。 iN。 ++i) { 本科毕业设计论文 13 v[i] = /* whatever */ } 但是这样很不方便,尤其是当我们想给 v 赋一系列不同的值时,在 for 循环中是比较麻烦的。 当然也可以用下面这种方式实现: double var[5] = { , , , 1, }。 Vectordouble v(var, 5)。 但这种方法的不便之处是使用了局部变量。 依我来看,最理想的 方法是把初始化列表放到构造函数中,如下: Vectordouble v({ , , , 1, }, 5)。 // Error – invalid 不幸的是这不符合 C++的语法规则,变通一下,使用如下方式: Vectordouble v((double[]) { , , , 1, }, 5)。 // Usually OK 这种方法通常是不会错的,但是也有可能有些编译器会报错,我也不知道这算不算标准 C++语法,因为没有一本 C++书 (我读过的 )讲到过这种初始化方式。 为了解决这个问题,我使用了 操作符,把我的类对象当做标准输出。 从而可以使用如下方式进行初始化: Vectordouble v(5)。 v , , , 1,。 //或者 v 1。 输入数据的个数必须和对象的大小一致,否则会触发库中的出错处理函数。 上面的方式的优点是,初始化列表里的数据不限制为常量。 通常来说,初始化列表必须是在编译时可确定的,但用上面的方式,初始化列表里的 元素可以使变量,甚至是一个函数的返回值,只要能转换为 Vector模板对应的实例化类型就可以了。 当然 v也可以在其他任何时候重新使用此方法赋值。 另外,由于使用标准库的 valarray模板,所以在所有这些类的实现中,甚至没有主动使用 C++标准内存分配和删除操作符 new, delete,一个也没有出现。 最后, GneVector类和 AlomostVector类都含有纯虚函数,所以无法实例化,这正是我想要的,给用户使用的类是 Vector、 VectorView和 ConstVectorView三个类。 矩阵 GSL 提供的矩阵类型使用起来非常麻烦,由于是对 c 语言中的数组进行包装,所以用户时刻都要注意内存的变化,花费大量精力减少内存泄露 ,并且每种数据类型都有不同的函数版本,且不支持用户自定义类型,所以我决定使用 GSL的算法,重写构架矩阵类,并且给出 C++的接口,支持多种类型,包括未知的用户自定义类型,尽量减少用户对程序本身的维护工作量,使用户能专注于算。
阅读剩余 0%
本站所有文章资讯、展示的图片素材等内容均为注册用户上传(部分报媒/平媒内容转载自网络合作媒体),仅供学习参考。 用户通过本站上传、发布的任何内容的知识产权归属用户或原始著作权人所有。如有侵犯您的版权,请联系我们反馈本站将在三个工作日内改正。