Referrence:
Jim Blinn, "Optimizing C++ Vector Expression", in IEEE database
Kenneth I. Joy, "the Vector Data Type", http://graphics.cs.ucdavis.edu/CppNotes/homepage.html
PART I: on Constructor:
"All classes should have a copy constructor and an assignment operator."
That means, we should add two functions:
"Vector(const Vector&); and Vecotr& operator=(const Vector&);"
together with
"Vector(const double, const double, const double =0.0)"
原因是安全并且方便 (参考effective C++第三章, rule 11)
and consider that
Vecotr& operator=(const Vector&)
the input and output of operator is the same.
PART II: on output and Serialize
暂时不管他
PART III operator calling
试试严格遵守"没有重复代码的规定"
Vector& operator+=(const Vector& v2)
{
_x+=v2._x; _y+=v2._y; _z+=v2._z;
return *this;
}
int operator== (const Vector& v1, const Vector &v2)
{
if((v1._x==v2._x)&&(v1._y==v2._y)&&(v1._z==v2._z))
return TRUE;
else
return FALSE;
}
在这个基础上,定义
Vector& operator+(const Vector& v1, const Vector &v2)
{
return Vector(A) +=B;
}
int operator!= (const Vector& v1, const Vector &v2)
{
return(!(v1==v2));
}
看起来不错,但实际上operator+定义的不好。因为这样增加了一个Vector(A)的创建对象的开销。
我敢肯定matlab不会这样干的。希望下次可以研究一下matlab的早期代码。
Part IV 随心所欲的计算
Part of the vast popularity of C++ is its class structure and operator overloading features
that allow the definition of mathematical operations for many class. We should know we can
make the C++ act as matlab!
接着讨论operator+.如果我们不搞得那么花哨的话我们可以定义operator+的返回值是Vector 而不是Vector&
注意opertator+ 与operator=的情况是完全不一样的!
Vector operator+ (const Vector& v1, const Vector& v2)
{
Vector vv;
vv._x = v1._x+v2._x;
vv._y = v1._y+v2._y;
vv._z = v1._z+v2._z;
return(vv);
}
这样可以定义 *, /,-,+.
其他的,matlab里有.*,./,.-,.+.可以试试
另外,定义 Vector cross(const Vector& v1, const Vector& v2);
double dot(const Vector& v1, const Vector& v2);
void Vector::normalize();
double Vector::length();
最后,考虑operator重载,Vector operator+(float f1)等等。
当然,要想像matlab一样随心所欲,还有三件事
1.试试模板之类的东西。matlab可以不管int double 通吃的。
2.和矩阵的计算,接口
3.matlab 可以 d = [a,b,c]. C++好像只能d = vector(a,b,c)了。凑合着用了
这三条,以后再说吧.
Part V 编译错误
这玩意极其让人讨厌。#是万恶之源。std更是把这种罪恶推到了极点。
多用const吧。
1. we should know the difference between const char *p (*p='c' is not allowed)
and char* const p (p++ is not allowed);
2. we should know the reason why Vector dot(const Vector&, const Vector &)
instead of Vector dot(Vector&,Vector &). Yes, one reason is it is more safe.
But another reason, if we define Vector dot(Vector&, Vector &), we will get
errors when using: a = dot(v1+v2,v3). The compiler will not allow you to change
(v1 + v2)!
3. do not forget to declare a const function: double length()const; will not
change the data members of the class.
Part VI 效率
C++运行比较慢就在于创建对象的开销。 一个奇怪的现象是C++大规模矩阵计算未必赶得上matlab.
至于其他的软件,至少我觉得photoshop远远比一般的图像处理程序快的多。优化还是很重要的啊。
上面的Vector实现比较费时的地方是每个operator+里面都要创建一个Vector对象
然而,一个tricky的做法是采用"容器",而不是数据对象
class Sum{
const Vector &L;
const Vector &R;
public:
Sum(const Vector& Linit, const Vector& Rinit):L(Linit),R(Rinit){;}
float operator[](int i)const {return L[i]+R[i];}
}
void Vector::Evaluate(const Sum& e){
v[0]=e[0];v[1]=e[1];v[2]=e[2];
}
Sum operator+(const Vector& A,const Vector& B){
return Sum(A,B);
}
恩,这种东西真难维护。 :-P
不过呢,用Visitor模式,定义void Vector::Evaluate(const Function& e),
然后用Function 派生出各个类, Sum, Product....,各个类实现虚函数
operator[]。比如Sum::operator[](int i)是{return L[i]+R[i]}
而Product::operator[](int i)则是{return s*V[i]}.
漂亮把?
----yes, but.... do you know the cost of virtual function?
根据Berlin的结果,用Visitor模式的效率还不如最土的办法。:-(
在effective c++中,41号条款告诉我们,
"如果类型T不影响类的行为T,你可以使用模板。如果T影响行为,你就需要虚函数,从而要使用继承。"
能不能把上面的trick用template 表示呢? 模板的效率好像还不错,想想stl就知道了
ok,let's go
//Sum<L,R>
template<class LT,class RT>
class Sum{
const LT &L;
const RT &R;
public:
Sum(const LT& Linit, const RT& Rinit):L(Linit),R(Rinit){;}
float operator[](int i)const{return L[i]+R[i];}
};
//Product<V>
template<class VT>
class Product{
float s;
const VT& V;
public:
Product(const float sinit,const VT& Vinit):s(sinit),V(Vinit){;}
float operator[](int i)const{return s*V[i];}
};
// class Vector
class Vector{
...
template <class T>
Vector(const T& e){
Evaluate(e);
}
template<class T>
void Evaluate(const T& e){
v[0]=e[0];v[1]=e[1];v[2]=e[2];
}
template<class T>
Vector& operator=(const T& e){
Evaluate(e);
return this;
}
}
什么感觉?...有一点喘不过来气了。
看起来已经到了极限了。但是这只是针对3*Vector 或者Vector + Vector来说的。
想想如果计算a+3*(b+c),实际上是Sum(Vector,Product(Sum(Vector,Vector))).我们能不能将中间步骤
进一步简化呢?
可以的。不过需要进一步使用template.这个以后再看吧。可以去看Blinn的文章。
最后抄一段Blinn的话
Every programming language has a gimmick.
The gimmick of C++ is to put as much intelligence in the class library as possible,
to make things as easy as possible for the user of the those class. In spite of the fact
that there is a lot of complexity in the implementation of vector arithmetic, any user of
the Vector class does not see that complexity. They can create Vector class and perform
arithmetic on them with ease and with confidence. That is the classical trade-off in C++:
the need of the many out weigh the needs of the few.
最后一句很精彩。但也许允许我有一点不同意见。class不但要便于使用,也要便于维护。除非真的有速度
的工程需要,否则我想我愿意牺牲速度来换取可读性的。但是Cpp的可读性不一定是多重继承,接口,模板
也许更重要。我想考虑的是复杂的数据结构。比如一个从点的邻接矩阵找面,什么数据结构比较好,什么class
设计比较清晰?
那么回到Vector的讨论上来,如果我想Vector便于维护,至少可以从两个角度来想
第一,如果要将Vector扩展到4d, 也就是说homogeneous coordinates,那么Vector类的设计要怎么办?
第二,考虑Vector 和Matrix间的接口,应该怎么设计?
前一个可以去看Vxl,后一个可以去看matlab的设计。不过我要先自己想想。下次再写