Originariamente inviato da lolide
Non direttamente con gli array. Puoi creare una classe "wrapper" dove tieni un'array e fare l'overload di operator+ (ogni volta che fai un append devi riallocare un array ecc...
Occhio, non chiede un append, ma una somma membro a membro (quella che è in matematica la somma di due vettori).
Per il resto, tutto giusto, non è possibile farlo con due array "C-style", anche solo perché il tuo operatore dovrebbe restituire un array per valore, cosa non possibile.
Per la classe wrapper, una volta ho scritto una classe che implementa un vettore di dimensione fissata a compile time che gestisca le normali operazioni matematiche su di esso ridefinendo gli operatori (per somma, differenza, prodotto per scalare, prodotto interno, meno unario), e fornendo anche qualcosina in più come metodi (norma euclidea, distanza, versore, iteratori) e operatori C++ (output su stream). Se ti interessa, ecco qui:
codice:
#ifndef VECTOR_HPP_INCLUDED
#define VECTOR_HPP_INCLUDED
// Per size_t
#include <cstddef>
#include <cmath>
#include <iostream>
#include <stdexcept>
/*
La classe Vector è un vettore in senso matematico.
Ha una dimensione *fissata* a compile time (per cui è impossibile
assegnare un vettore di una dimensione ad uno di un'altra) e definisce
tutta una serie di operatori (somma, differenza, meno unario, prodotto per
scalare, divisione per scalare) tali per cui è possibile usarlo in maniera
"normale" in espressioni matematiche.
*/
// Un piccolo trucco di metaprogrammazione per fargli prendere automaticamente
// il tipo giusto per il prodotto per scalare.
// Di base usa come tipo per il prodotto per scalare il tipo di base...
template <typename TBaseType>
class VectorTraits
{
public:
// Tipo su cui si basa
typedef TBaseType TraitsBaseType;
// Il tipo usato per i prodotti per scalare
typedef TBaseType TraitsScalarType;
};
template<unsigned int N, typename TBaseType=double>
class Vector
: public VectorTraits<TBaseType>
{
public:
// La classe traits
typedef VectorTraits<TBaseType> Traits;
// Tipo usato per gli indici
typedef std::size_t SizeType;
// Lui stesso (per abbreviare)
typedef Vector<N, TBaseType> ThisType;
// "Importa" i typedef dei traits per comodità
typedef typename Traits::TraitsBaseType BaseType;
typedef typename Traits::TraitsScalarType ScalarType;
typedef BaseType * iterator;
typedef const BaseType * const_iterator;
// Costruttore
Vector()
{
// Ad un certo punto pensavo di inizializzare tutto al valore di
// default, ma per i tipi-classe già avviene, mentre per i POD
// who cares? :)
}
// Operatore di accesso agli elementi
BaseType & operator[](SizeType Index)
{
if(Index>=N)
throw std::out_of_range("Index out of range.");
return v[Index];
}
// ... e relativa versione const
const BaseType & operator[](SizeType Index) const
{
if(Index>=N)
throw std::out_of_range("Index out of range.");
return v[Index];
}
/*
Operatori matematici
Tutti gli operatori in versione non-assegnamento usano la versione
con assegnamento restituendo il relativo oggetto temporaneo
*/
// Prodotto per scalare
ThisType operator*(const ScalarType & Right) const
{
ThisType ret(*this);
return ret*=Right;
}
ThisType & operator*=(const ScalarType & Right)
{
for(SizeType i=0; i<N; i++)
(*this)[i]*=Right;
return *this;
}
// Prodotto interno
// Applicato a Vector<Vector > potrebbe dare risultati bizzarri
ScalarType operator*(const ThisType & Right) const
{
ScalarType ret=0.;
for(SizeType i=0; i<N; i++)
ret+=(*this)[i]*Right[i];
return ret;
}
// La norma deriva direttamente dalla definizione del prodotto interno
ScalarType Norm() const
{
return std::sqrt((*this)*(*this));
}
// Distanza = norma della differenza tra i due punti
ScalarType Distance(const ThisType & Right) const
{
return ((*this)-Right).Norm();
}
// Versore = vettore/norma
ThisType UnitVector() const
{
return (*this)/(this->Norm());
}
// Divisione per scalare (se applicabile)
ThisType operator/(const ScalarType & Right) const
{
ThisType ret(*this);
return ret*(1./Right);
}
ThisType & operator/=(const ScalarType & Right)
{
(*this)*=(1./Right);
}
// Somma
ThisType operator+(const ThisType & Right) const
{
ThisType ret(*this);
return ret+=Right;
}
ThisType & operator+=(const ThisType & Right)
{
for(SizeType i=0; i<N; i++)
(*this)[i]+=Right[i];
return (*this);
}
// Differenza
ThisType operator-(const ThisType & Right) const
{
ThisType ret(*this);
return ret-=Right;
}
ThisType & operator-=(const ThisType & Right)
{
for(SizeType i=0; i<N; i++)
(*this)[i]-=Right[i];
return (*this);
}
// Meno unario (cambio di segno)
ThisType operator-()
{
ThisType ret(*this);
for(SizeType i=0; i<N; i++)
ret[i]=-ret[i];
return ret;
}
// Iteratori (per l'uso tramite STL)
iterator begin()
{
return v;
}
const_iterator begin() const
{
return v;
}
iterator end()
{
return v+N;
}
const_iterator end() const
{
return v+N;
}
protected:
// Array interno
BaseType v[N];
};
// Di nuovo il prodotto per scalare; necessario per far sì che si possa usare
// anche se lo scalare sta sulla sinistra dell'espressione
template<unsigned int N, typename TBaseType, typename TScalarType>
Vector<N, TBaseType> operator*(const TScalarType & Left, const Vector<N, TBaseType> & Right)
{
// Di fatto richiama l'operatore già definito sopra
return Right*Left;
}
// Specializzazione parziale nel caso in cui la classe base sia un Vector a
// sua volta (il tipo scalare per un Vector di Vector resta il tipo scalare
// dei suoi componenti)
template<unsigned int N, typename TVectorBaseType>
class VectorTraits< Vector<N, TVectorBaseType> >
{
public:
// Tipo su cui si basa
typedef Vector<N, TVectorBaseType> TraitsBaseType;
// Il tipo usato per i prodotti per scalare
typedef typename Vector<N, TVectorBaseType>::ScalarType TraitsScalarType;
};
// Scrive il vettore sullo stream di output specificato
template<unsigned int N, typename TBaseType>
std::ostream & operator<<(std::ostream & Os, Vector<N, TBaseType> Vec)
{
typedef Vector<N, TBaseType> VT;
Os<<"{";
for(typename VT::SizeType i=0; i<N; i++)
{
Os<<Vec[i];
if(i!=N-1)
Os<<"; ";
}
Os<<"}";
return Os;
}
#endif
Supporta anche dei Vector di Vector, nel qual caso il prodotto per scalare opera su tutte le componenti di tutti i sotto-Vector, mentre il prodotto interno fa cose bizzarre (di fatto restituisce la somma dei prodotti interni tra i sotto-Vector corrispondenti, che non vuol dire niente dal punto di vista matematico).