Небольшой 3D и 4D вектор ЖКХ


Я хобби программиста и начал 2 месяца назад с C++. Я немного знаком с Python, и я узнал все это через интернет-уроки.

Я ищу вашу помощь, так как у меня нет наставника, я хотел бы получить комментарий по поводу моего стиля программирования. Я использовал эту небольшую "библиотеку", чтобы создать Snake4D игры (см. Внизу вопрос для получения дополнительной информации).

Вот маленькая программа, которая обрабатывает математические векторы, 4D и 3D. В частности, я прошу вас найти какие-либо улучшения читаемости кода и алгоритмов.

Вот "ВМК.H-файл":

class V4{
private:
    double coords[4];
 public:
    V4();
    V4(double x, double y, double z, double w);
    ~V4();

    void set_cooord(int i, double x); //set_coord (index of coord i, value x)

    double module();
    double operator[](unsigned int i);

    void operator =(V4);
    V4 operator +(const V4);
    V4 operator -(const V4);
    V4 operator *(double k); //moltiplication of vector by a scalar k

    double dot4(V4); //the dot product

    V4 cross(V4 u, V4 v,V4 w); //the cross product
};

Вот файл "vec.cpp":

/****************
V4 class
*****************/
V4::V4(){
    //set all coords to 0. if it's called without specific coord
    coords[0] = 0.;
    coords[1] = 0.;
    coords[2] = 0.;
    coords[3] = 0.;
}

V4::V4(double x, double y, double z, double w){
    coords[0] = x;
    coords[1] = y;
    coords[2] = z;
    coords[3] = w;
}

V4::~V4(){}//nothing to destroy?

void V4::set_cooord(int i, double x){ //i index, x value
    coords[i] = x;
}

double V4::module(){
    double sum = 0;
    for(int i= 0; i<4; i++){
        sum += coords[i]*coords[i];
    }
    return sqrt(sum);
}

double V4::operator[](unsigned int i){
     //if(i > 4){return;}  //list index out of range ? how to throw give a compile error?
     return coords[i];
 }

void V4::operator =(V4 v1){
    for(int i= 0; i<4; i++){
        coords[i] = v1[i];
    }
}

V4 V4::operator+(V4 v1) {
    double c[4]; // array of 4 double which will be transfered to the returned vector
     for(int i= 0; i<4; i++){
         c[i] = coords[i] + v1[i];
     }
     return V4(c[0],c[1],c[2],c[3]);
 }

 V4 V4::operator-( V4 v1) {
     double c[4];
     for(int i= 0; i<4; i++){
         c[i] = coords[i] - v1[i];
     }
     return V4(c[0],c[1],c[2],c[3]);
 }


V4 V4::operator*(double k){
    double c[4];
    for(int i= 0; i<4; i++){
        c[i] = coords[i] * k;
    }
    return V4(c[0],c[1],c[2],c[3]);
}

double V4::dot4(V4 v1){
    double sum = 0;
    for(int i= 0; i<4; i++){
       sum += coords[i]*v1[i];
    }
    return sum;
}


// requires three external vector and doesn't take any coords of the actual vector
//intended use:
// V4 v1(x,y,z,w), v2(x,y,z,w), v3(x,y,z,w), result, op;
// result = op.cross(v1,v2,v3)
V4 V4::cross(V4 u, V4 v, V4 w){
    //source Steve Hollasch master thesis
    //partial product
    double A = (v[0]*w[1])-(v[1]*w[0]);
    double B = (v[0]*w[2])-(v[2]*w[0]);
    double C = (v[0]*w[3])-(v[3]*w[0]);
    double D = (v[1]*w[1])-(v[2]*w[1]);
    double E = (v[1]*w[3])-(v[3]*w[1]);
    double F = (v[2]*w[3])-(v[3]*w[2]);

    double x =  (u[1]*F)-(u[2]*E)+(u[3]*D);
    double y = -(u[0]*F)+(u[2]*C)-(u[3]*B);
    double z =  (u[0]*E)-(u[1]*C)+(u[3]*A);
    double wc = -(u[0]*D)+(u[1]*B)-(u[2]*A); //defined as wc to not conflic with w vector

    return V4(x,y,z,wc);
}

Вот источник (.H и .СРР-файл) .

Я уже вижу некоторые улучшения:

  1. Я использовать векторы в качестве общественных членов, потому что если они частные, я не могу получить доступ ко всем действительно комфортные функции, которые они предлагают.
  2. Вместо того, чтобы дать вершине рука об руку для создания гиперкуба, там должен быть алгоритм, который делает это.
  3. Она может быть использована в общего назначения, класс В , содержащий основные методы и переменные инт измерения специализируется на В3 и В4 , который наследует класс В.

ЗЫ: я сделал небольшой клип, который показывает Snake4D игры написан на C++ и Qt и OpenGL.



1858
3
задан 22 августа 2011 в 05:08 Источник Поделиться
Комментарии
1 ответ

Очень хорошо.

Пару моментов:

Я бы избавилась от метода set (), и позволяет работать оператором[]. Для этого вам нужно вернуть значение по ссылке.

double &  operator[](unsigned int i);
// ^^^ Return double by reference.

Это позволяет вам делать;

V4 x;
x[1] = 12;

При передаче объектов в качестве параметров обычно лучше передавать по константной. Это означает, что не будет сделана копия и исходный объект не может быть изменен способ его использования:

V4 operator +(V4 const & rhs);
^^^

Обратите внимание, я всегда ставлю модификатор const справа от типа (а не левой). Понятно, что это религиозная война, так что выбрать сторону и придерживайтесь его (есть только один побочный инстанции-это огромная разница). Но я нахожу это делает чтение имени типа легче (как типы читаются справа налево с const всегда привязка к левой (кроме случаев, когда это левый лексемы в тип затем он связывает право).

Методы, которые не изменяют состояние объекта, объявленного как const:

V4 operator -(V4 const & rhs) const;
// ^^^^^ indicates that calling this method will not
// change the state of the object.

Примечание: это означает, что вы должны предоставить две версии оператора[] нормальная такая, которая позволяет мутации и const версии, которые могут использоваться в контекстах, где оно только для чтения.

double&        operator[](unsigned int i)        { return coord[i];}
double const& operator[](unsigned int i) const { return coord[i];}

Примечание: доступ к элементу массива не проверяется границы массива. Как правило, вы не проверите, а мы не хотим возлагать дополнительное бремя на ответственность только потому, что есть плохие разработчики. Но это традиционные для добавить в() метод, который делает такую же работу как оператор [], но и проверяет границы доступа к массиву.

double&        at(unsigned int i)        { if (i > 3) {throw std::range_error("BLA");} return coord[i];}
double const& at(unsigned int i) const { if (i > 3) {throw std::range_error("BLA");} return coord[i];}

Реализовывая оператор + - * / это легко сделать, если выполнить их с точки зрения += -= *= /=. Это также предоставляет пользователю вашего объекта возможность более эффективно использовать свой класс, когда новый объект не требуется (хотя это должно быть вторичным, хотя).

V4 operator *(V4 const & rhs) const;
V4 operator *=(V4 const & rhs); // This does change the sate of the object

V4 V4::operator*(V4 const& rhs) const { V4 result(*this); result *= rhs; return result;}

Используя цикл for-это просто. Но иногда это может быть проще использовать стандартные алгоритмы для выполнения простых задач за короткое контейнеров:

double sum = 0;
for(int i= 0; i<4; i++){
sum += coords[i]*coords[i];
}

Это может быть заменен:

sum = std::accumulate(coords, coords + 4, 0);

Вы можете найти хорошую документацию здесь: http://www.sgi.com/tech/stl/table_of_contents.html (искать в разделе: 5 алгоритмов)

В мото не делать лишнюю работу. Не писать методы, которые ничего не делают:

V4::~V4(){}//nothing to destroy?

Удалить этот. Класс автоматически предоставляет desttructor, что будет правильно не уничтожать.

Мне на самом деле нравится, используя Void в качестве возвращаемого типа уступки (я думаю это не недостаток). Но традиционно присваивания должен возвращать ссылку на себя. Тогда в этом случае объект может быть частью цепочки назначение.

V4  a;
V4 b;
V4 c;

a = b = c; // assignment chaining.
// It also allows you to pass the object as a parameter to a mehtod:

doStuff( a = b); // Assign a to b. Then call doStuff using a.

Это также хорошая идея, чтобы определить потоковые операторы для большинства классов. Это allowsd вы для сериализации и де-сериализации класса в поток (файл/строку и т. д.).

Поэтому сейчас класс выглядит так.

class V4
{
double coords[4];
public:
V4();
V4(double x, double y, double z, double w);

double module() const;
double& operator[](unsigned int i) {return coords[i];}
double const& operator[](unsigned int i) const {return coords[i];}

V4& operator = (V4 const& rhs);
V4& operator +=(V4 const& rhs);
V4& operator -=(V4 const& rhs);
V4& operator *=(double k); //moltiplication of vector by a scalar k

V4 operator +(V4 const& rhs) const {V4 result(*this); result += rhs; return result;}
V4 operator -(V4 const& rhs) const {V4 result(*this); result -= rhs; return result;}
V4 operator *(double rhs) const {V4 result(*this); result *= rhs; return result;}

double dot4(V4 const& rhs) const; //the dot product

V4 cross(V4 const& u, V4 const& v,V4 const& w) const; //the cross product
};

Затем остальные интересные из них:

double V4::module() const
{
return std::sqrt(std::accumulate(coords, coords + 4, 0.0);
}

V4& V4::operator +=(V4 const& rhs)
{
std::transform(coord, coord+4, rhs.coord, coord, std::plus);
return *this;
}
V4& V4::operator -=(V4 const& rhs)
{
std::transform(coord, coord+4, rhs.coord, coord, std::minus);
return *this;
}
V4& V4::operator *=(double k)
{
std::transform(coord, coord+4, coord, std::bind1st(std::multiplies, k));
return *this;
}

6
ответ дан 23 августа 2011 в 01:08 Источник Поделиться