3D Vector Class, C++

Here's a little class I whipped together to represent a 3D Vector. It has most of the basic 3D Vector functions like: Dot product, cross product, normalize\unitize, length, length squared. And all the overloaded operators needed to make the class easy to use.

To get started quickly just create an empty project, Windows Console App. Or, if you don't want to hand-type or copy and paste, here is the project in a zip file, Click here to download.

Header file: Vector3.h

#ifndef VECTOR_3
#define VECTOR_3

#pragma once

#include <math.h>
#include <ostream>

class Vector3
{
public:
Vector3(void);
explicit Vector3(const float x, const float y, const float z);

// Copy constructors
Vector3(const Vector3& rhs);

~Vector3(void);

bool operator==(const Vector3& rhs) const { return ( (x == rhs.x) && (y == rhs.y) && (z == rhs.z) ); }
bool operator!=(const Vector3& rhs) const { return ( (x != rhs.x) || (y != rhs.y) || (z != rhs.z) ); }
Vector3 operator+(const Vector3& rhs) const;
void operator+=(const Vector3& rhs);
Vector3 operator-(const Vector3& rhs) const;
Vector3 operator-(void) const;
void operator-=(const Vector3& rhs);
void operator*=(const int scalar);
void operator*=(const float scalar);

// Non-member operators get a friend declaration
friend Vector3 operator*(const Vector3& vector, const int scalar);
friend Vector3 operator*(const Vector3& vector, float scalar);
friend Vector3 operator*(const int scalar, const Vector3& vector);
friend Vector3 operator*(const float scalar, const Vector3& vector);
friend std::ostream& operator<< (std::ostream& ofs, const Vector3& vector);

inline void Flip(void) { x = -x; y = -y; z = -z; }

inline float Dot(const Vector3& rhs) const { return (x * rhs.x + y * rhs.y + z * rhs.z); }

Vector3 Cross(const Vector3& rhs) const;

float Length(void) const { return sqrtf( LengthSqr() ); }

inline float LengthSqr(void) const { return (x * x + y * y + z * z); }

float Unitize(void);

void Reflect( const Vector3& rhs );

static Vector3 Reflect( const Vector3& first, const Vector3& second );
static Vector3 GetLongest( const Vector3& first, const Vector3& second );

static const Vector3 Left;
static const Vector3 Right;
static const Vector3 Up;
static const Vector3 Down;
static const Vector3 Forward;
static const Vector3 Backward;

static const Vector3 UnitX;
static const Vector3 UnitY;
static const Vector3 UnitZ;

static const Vector3 Zero;

// Vector is a high-performance class, and as these members are accessed so often we don't want
// accessors cluttering up the code. This is a rare exception to the rule that member variables should
// always be private.

float x;
float y;
float z;
};

#endif VECTOR_3

Implementation File, Vector3.cpp:

#include"Vector3.h"

#include <sstream>

const Vector3 Vector3::Right(1.f, 0.f, 0.f);
const Vector3 Vector3::Up(0.f, 1.f, 0.f);
const Vector3 Vector3::Forward(0.f, 0.f, 1.f);
const Vector3 Vector3::Left(-1.f, 0.f, 0.f);
const Vector3 Vector3::Down(0.f, -1.f, 0.f);
const Vector3 Vector3::Backward(0.f, 0.f, -1.f);

const Vector3 Vector3::UnitX(1.f, 0.f, 0.f);
const Vector3 Vector3::UnitY(0.f, 1.f, 0.f);
const Vector3 Vector3::UnitZ(0.f, 0.f, 1.f);

const Vector3 Vector3::Zero(0.0f, 0.0f, 0.0f);

Vector3::Vector3(void) :
x(0.0f), y(0.0f), z(0.0f)
{
}

Vector3::Vector3(const float x, const float y, const float z)
{
    this->x = x;
    this->y = y;
    this->z = z;
}

// Copy constructor
Vector3::Vector3(const Vector3& rhs)
{
    x = rhs.x;
    y = rhs.y;
    z = rhs.z;
}

Vector3::~Vector3(void)
{
}

Vector3 Vector3::operator+(const Vector3& rhs) const
{
    Vector3 newVector;
    newVector.x = x + rhs.x;
    newVector.y = y + rhs.y;
    newVector.z = z + rhs.z;
    return newVector;
}

void Vector3::operator+=(const Vector3& rhs)
{
    x += rhs.x;
    y += rhs.y;
    z += rhs.z;
}

Vector3 Vector3::operator-(const Vector3& rhs) const
{
    Vector3 newVector;
    newVector.x = x - rhs.x;
    newVector.y = y - rhs.y;
    newVector.z = z - rhs.z;
    return newVector;
}

Vector3 Vector3::operator-(void) const
{
    Vector3 newVector;
    newVector.x = -x;
    newVector.y = -y;
    newVector.z = -z;
    return newVector;
}

void Vector3::operator-=(const Vector3& rhs)
{
    x -= rhs.x;
    y -= rhs.y;
    z -= rhs.z;
}

void Vector3::operator*=(const int scalar)
{
    x *= scalar;
    y *= scalar;
    z *= scalar;
}

void Vector3::operator*=(const float scalar)
{
    x *= scalar;
    y *= scalar;
    z *= scalar;
}

Vector3 operator*(const Vector3& vector, const int scalar)
{
    Vector3 newVector(vector.x * scalar, vector.y * scalar, vector.z * scalar);
    return newVector;
}

Vector3 operator*(const Vector3& vector, const float scalar)
{
    Vector3 newVector(vector.x * scalar, vector.y * scalar, vector.z * scalar);
    return newVector;
}

Vector3 operator*(const int scalar, const Vector3& vector)
{
    Vector3 newVector(vector.x * scalar, vector.y * scalar, vector.z * scalar);
    return newVector;
}

Vector3 operator*(const float scalar, const Vector3& vector)
{
    Vector3 newVector(vector.x * scalar, vector.y * scalar, vector.z * scalar);
    return newVector;
}

std::ostream& operator<< (std::ostream& os, const Vector3& vector)
{
    std::stringstream stream;
    stream << "X: " << vector.x << ", Y: " << vector.y << ", Z: " << vector.z;
    os.write(const_cast<char*>(stream.str().c_str()), static_cast<std::streamsize>(stream.str().size() * sizeof(char)) );
    return os;
}

Vector3 Vector3::Cross(const Vector3& rhs) const
{
    Vector3 vector( (y * rhs.z) - (z * rhs.y), (z * rhs.x) - (x * rhs.z), (x * rhs.y) - (y * rhs.x) );
    return vector;
}

float Vector3::Unitize(void)
{
    const float length = Length();
    const float num = 1.0f / length;
    x *= num;
    y *= num;
    z *= num;
    return length;
}

void Vector3::Reflect( const Vector3& normal )
{
    constfloat dotProductTimesTwo = Dot(normal) * 2.0f;
    x -= dotProductTimesTwo * normal.x;
    y -= dotProductTimesTwo * normal.y;
    z -= dotProductTimesTwo * normal.z;
}

Vector3 Vector3::Reflect( const Vector3& vector, const Vector3& normal )
{
    Vector3 newVector;
    const float dotProductTimesTwo = vector.Dot(normal) * 2.0f;
    newVector.x = vector.x - (dotProductTimesTwo * normal.x);
    newVector.y = vector.y - (dotProductTimesTwo * normal.y);
    newVector.z = vector.z - (dotProductTimesTwo * normal.z);
    return newVector;
}

Vector3 Vector3::GetLongest(const Vector3& first, const Vector3& second)
{
    if ( first.LengthSqr() > second.LengthSqr() )
        return first;

    return second;
}


And now lets try it out, here is the main.cpp file:

#include <iostream>
#include "Vector3.h"

using namespace std;

int main()
{
// Demonstrates other copy constructor, static member variable usage, and unary operator-
const Vector3 backward(-Vector3::Forward);

// Demonstrates cross product
const Vector3 right( Vector3::Forward.Cross(Vector3::Up) );

// Demonstrates constructor
Vector3 testVect(1.0f, 0.0f, 1.0f);

// Demonstrates operator<<
cout << testVect << '\n';
// Demonstrates unitize method
testVect.Unitize();
cout << "Unitized: " << testVect << '\n';

// Demonstrates reflect method
const Vector3 reflection( Vector3::Reflect( testVect, backward ) );
cout << "Reflected off surface with 'backward' as the normal, " << reflection << '\n';

// Demonstrates operator*, we don't const 'doubleFwd' because we want to use Unitize later.
Vector3 doubleFwd(Vector3::Forward * 2);

cout << "Double Forward, " << doubleFwd << '\n';
cout << "Double Forward Length: " << doubleFwd.Length() << '\n';
doubleFwd.Unitize();
cout << "Unitize Double Forward, now what is the length?: " << doubleFwd.Length() << '\n';

cout << "Press any key to quit. ";

char blah = ' ';
cin.get(blah);

return -1
;
}