I'm trying to use + to add 2 vector (mathematical vector). Here's my code:
class Vector{
double v[Max_size];
int dim;
public:
int getDim() const;
Vector();
Vector(int n);
Vector(const Vector& a);
Vector add(const Vector&b);
friend Vector operator+(Vector summand1, Vector summand2);
};
Operator overloading:
Vector operator+(Vector summand1, Vector summand2){
int dim1 = summand1.getDim();
int dim2 = summand2.getDim();
assert(dim1 == dim2);
Vector sum(dim1);
int i;
for(i = 0; i < dim1; i++){
sum.v[i] = summand1.v[i] + summand2.v[i];
}
return sum;
}
And how I use it:
Vector m = v+t;
When I run the code, it always shows that m is (0,0) (2D vector), which is the default value generated by the constructor. What's wrong with it? Thanks!
Your copy constructor:
Vector::Vector(const Vector& a){
dim = a.dim;
Vector(dim);
}
correctly sets the value of the dim member, but has not other side effect.
You should have a variant of the following code:
Vector::Vector(const Vector& a) : dim(a.dim) {
std::copy(std::begin(a.v), std::end(a.v), v);
}
This will actually copy the data present in the parameter, and you will see the correct behavior for the code:
// Copy constructor called here, but did not correctly copy the data before.
Vector m = v + t;
For a better (by that I intend simpler and safer) Vector class, if you have access to a compiler that is at least C++11 compliant, you can write:
class Vector{
std::array<double, Max_size> v; // Note the std::array here.
int dim;
public:
int getDim() const;
Vector();
Vector(int n);
Vector(const Vector& a);
Vector add(const Vector&b);
friend Vector operator+(Vector summand1, Vector summand2);
};
The std::array will take care of everything, provided you write your copy constructor like this:
Vector::Vector(const Vector& a) : v(a.v), dim(a.dim) {
}
Or, even better, you could then let the compiler generate the copy constructor itself, with the same behavior.
Related
Consider a simple vector class realization:
#include <algorithm>
class Vector {
public:
Vector(int _elementsCount)
: elementsCount(_elementsCount)
, elements(new float[_elementsCount])
{}
~Vector() {
delete[] elements;
}
Vector(const Vector& rhs) {
elementsCount = rhs.size();
elements = new float[elementsCount];
for (int i = 0; i < elementsCount; ++i)
(*this)[i] = rhs[i];
}
float& operator [](int i) {
return elements[i];
}
float operator [](int i) const {
return const_cast<Vector&>(*this)[i];
}
int size() const {
return elementsCount;
}
/*// Dot product
float operator *(const Vector& v) {
float res = 0;
for (int i = 0; i < size(); ++i)
res += (*this)[i] * v[i];
return res;
}*/
private:
int elementsCount;
float* elements;
};
// Multiplication by a scalar
Vector operator *(const Vector& v, float k) {
Vector res(v.size());
for (int i = 0; i < v.size(); ++i)
res[i] = v[i] * k;
return res;
}
// Dot product
float operator *(const Vector& v1, const Vector& v2) {
float res = 0;
for (int i = 0; i < std::min(v1.size(), v2.size()); ++i)
res += v1[i] * v2[i];
return res;
}
void main()
{
Vector v(2);
v * 3; // ambiguous
}
This code compiles. But if we uncomment * operator realization in the class and comment its global realization (dot product function), then there will be an error "'Vector::operator *': 2 overloads have similar conversions", because there is an ambiguity: whether to call the multiplication by a scalar or to interpret 3 as an argument to a parametrized constructor and to call the dot product. This makes sense. But I don't get what's the difference of declaring the * operator as a member function or as a global function. I thought they should be the same in the example like above, but it's not the case.
Added. The thing I most interested in is not how to avoid the ambiguity, but why there is an ambiguity in one case (when * is declared as a member) and there is no one in the other (when * is declared as a global function).
You need to make your constructor explicit:
explicit Vector(int _elementsCount) { ... }
The reason for the ambiguity is that the compiler can't decide whether it should implicitly convert a int value to a Vector and invoke Vector::operator*, or implicitly convert a int value to a float and use operator*(const Vector&, float).
By using explicit, such conversions are forbidden, and you must use Vector(3) if you want "3" to be a Vector.
As a side-note, you should make the operator const, since it does not modify the object. Making it const will also allow it to be used with a const Vector:
float operator *(const Vector& v) const { ... }
Beware that will still conflict with your other overload:
float operator *(const Vector& v1, const Vector& v2)
There is no reason to have both. Choose either the member function or the global function and remove the other.
hi i am trying to create matrix class and i want to assign like matrix[0][2]=3
i checked form and found a solution with array but i want to do with vector and could not understand why does not it works ?
template<class T>
class Matrix
{
public:
Matrix(int a, int b)
{
vector<vector<T> > vec( a , vector<T> (b, 0));
matrixData = vec;
}
class Array1D
{
public:
Array1D(vector<T> a):temp(a) {}
T& operator[](int a)
{
return temp[a];
}
vector<T> temp;
};
vector<vector<T> > matrixData;
Array1D operator[] (int a)
{
return Array1D(matrixData[a]);
}
};
int main()
{
Matrix<int> n(3,5);
n[0][2] = 123; //assign
cout<<n[0][2]; // wrong output getting 0
}
You have to change Array1D implementation to:
class Array1D
{
public:
Array1D(vector<T>& a):temp(a) {}
T& operator[](int a)
{
return temp[a];
}
vector<T>& temp;
};
without this, every time you call operator[] on matrix you access temporary vector. Hence, every call n[0] works on different vector. So any previous modifications cannot be saved, and you always see 0 as result.
With the above change, you access original vector of matrix by Array1D proxy class.
Demo
You are returning the wrong type from the Matrix::operator[]. You need to return a nested vector by reference, so that you can chain the next [] to it:
vector<T>& operator[] (int a)
{
return matrixData[a];
}
In fact, you don't need the internal Array1D class at all for this purpose, since vector already has an operator[], and you can remove it entirely.
Here's a working demo.
For my own created Vector class:
class Vector
{
private:
double* elem;
int n;
public:
Vector();
Vector(const int s);
Vector(Vector&);
~Vector();
void print();
void set(const int, const double);
double get(const int) const;
int size() const;
double norm() const;
Vector add(const Vector&) const;
Vector subtract(const Vector&) const;
double scalar(const Vector&) const;
};
When I try to call the copy constructor:
Vector::Vector(Vector& x)
{
int count = 0;
n = x.n;
elem = new double[n];
while (count < n)
{
elem[n] = x.elem[n];
count++;
}
}
It copies the address instead of the elements of the vector. Does anybody have an idea why this happen?
P.S. I In the destructor I have written
delete []elem;
Because
Vector(Vector&);
it is not signature for a copy constructor. Right signature would be
Vector(const Vector&);
Compiler doesn't see user defined copy constructor and silently generates it's own default copy constructor which just make copy of
double* elem;
int n;
and doesn't care about allocation new memory and copying elements of array.
Vector::Vector(Vector& x)
{
int count = 0;
n = x.n;
elem = new double[n];
while (count < n)
{
elem[n] = x.elem[n];//here should be:elem[count] = x.elem[count]
count++;
}
}
I have a problem with my program in c++. I try to write copy constructor. Everything is good until I start copying elements from array from object that is applied as a reference.
I can print every element of applied array but I can't copy it to array in object that copy constructor will create.
Here's the code (I show only the header file and some methods that needs copy constuctor because all code is too long I think)
Header.h
#pragma once
# include <iostream>
# include <fstream>
# include <cmath>
using namespace std;
class Polynomial {
private:
int degree;
double* coefficients;
public:
static const string errors[5];
Polynomial(const Polynomial& wzor); // konstruktor kopiujacy
Polynomial(float n);
~Polynomial();
void setCoefficient(unsigned int i, double value);
double getCoefficient(unsigned int i);
double value(double x);
friend ostream & operator <<(ostream & out, Polynomial & p);
double operator[](const int index);
double operator()(double x);
void operator=(Polynomial &obiekt);
friend Polynomial operator+(Polynomial &obiekt,Polynomial &obiekt1);
friend Polynomial operator-(Polynomial &obiekt,Polynomial &obiekt1);
friend Polynomial operator~(Polynomial &obiekt);
friend Polynomial operator*(Polynomial &obiekt,Polynomial &obiekt1);
friend Polynomial operator*(Polynomial &obiekt,double x);
};
Polynomial::Polynomial(float n) {
if(n<0){
throw 0;
}
else if(floor(n)-n != 0){
throw 2;
}
degree=(int)n;
coefficients=new double [(int)n+1];
for(unsigned int i=0; i<n; i++) {
coefficients[i]=0.0;
}
coefficients[(int)n]=1.0;
}
Polynomial::Polynomial(const Polynomial &wzor){
degree=wzor.degree; // it's allright
for(int i=0; i<=wzor.degree; i++){
coefficients[i]=wzor.coefficients[i]; // compilator says that this line is wrong
}
}
Polynomial::~Polynomial(){
delete coefficients;
}
Polynomial operator+(Polynomial &obiekt,Polynomial &obiekt1){
Polynomial nowy(1);
if(obiekt1.degree > obiekt.degree){
nowy=obiekt1;
for(int i=0; i<=obiekt.degree; i++){
nowy.coefficients[i]=nowy.coefficients[i]+obiekt.coefficients[i];
}
}
else{
nowy=obiekt;
for(int i=0; i<=obiekt1.degree; i++){
nowy.coefficients[i]=nowy.coefficients[i]+obiekt1.coefficients[i];
}
}
return nowy;
}
class Polynomial {
private:
int degree;
double* coefficients; // Pointer to double
/* ... */
}
You have declared coefficients to be a pointer to double, not an array.
for(int i = 0; i <= wzor.degree; i++) {
coefficients[i] = wzor.coefficients[i]; // Error! No memory allocated.
}
Here you are trying to assign values to memory that doesn't exist. You need to allocate the array before you can assign element data to it. Also you should initialize members in the initialization list instead of the ctor body. Try something like this instead:
Polynomial::Polynomial(const Polynomial& wzor)
: degree(wzor.degree), coefficients(new double[wzor.degree + 1]) { // Init
for (int i=0;i<=wzor.degree;i++) {
coefficients[i]=wzor.coefficients[i];
}
}
Remember that the copy constructor is a constructor. It will construct a new instance of the object and you need to allocate new memory for the new copy.
Also in your destructor you must use delete[] instead of delete as you are deleting an array.
The assignment operator should be declared as:
Polynomial& operator= (const Polynomial& obiekt);
You should use type std::size_t for variables storing array indexes instead of int.
Finally I recommend using containers from the standard library instead of built in arrays, e.g. std::vector.
#include <vector>
std::vector<double> coefficients;
you can use the copy of the vector which means you do not have to implement it on your own.
And you do not have to do the delete stuff.
Use resize & [] or push_back methods to work on the string. Your degree will be coefficients.size().
You're assignment operator is wrong. It should be
Polynomial & operator=(const Polynomial &obiekt);
I am not the most experienced C++ programmer and new to this forum.
I hope this first post follows the rules.
My goal is to write a simple raytracer, but I am stuck on how to extend one of my classes.
The problem lies with operator overloading, but also design-patterns (I think). Here is my code:
class Vec{ //My vector class
protected:
double v[4]; //Fourth element not used...
public:
Vec();
Vec (double i, double j, double k);
Vec operator+ (const Vec& vec) const;
Vec operator- (const Vec& vec) const;
Vec & operator+=(const Vec& vec);
Vec & operator-=(const Vec& vec);
double operator*(const Vec& vec) const;
Vec operator*(double scalar);
//get operator
double& operator[](unsigned int i);
double operator[](unsigned int i) const;
//Vector assignment operator
Vec Vec::operator=(const Vec& vec);
//Scalar assignment operator
Vec Vec::operator=(double scalar);
};
Vec Vec::operator+(const Vec& vec) const{
return Vec(v[0]+vec.v[0], v[1]+vec.v[1], v[2]+vec.v[2]);
}
And
class Color : public Vec{
protected:
Vec col; //A Color should use all four elements in the array
//I.e Vec color(R,G,B,specular);
public:
//Vec Color::operator+(const Vec& vec) const; <-- this is wrong i know.
};
Just to be thorough, I do this in main:
Color myColor(1.2, 1.3, 2.3, 40);
Color myColor2(2.2, 3.4, 3.3, 30);
cout << (myColor+myColor2) << std::endl;
The program calls the Vec() default constructor returning an output of (0,0,0) which is clearly wrong....
Edit: The Vec class stores values like this
Vec::Vec () {
v[0] = 0; v[1] = 0; v[2] = 0;
}
Vec::Vec (double i, double j, double k) {
v[0] = i; v[1] = j; v[2] = k;
}
All overloaded operators work on double v[4] and return a Vec either a copy or reference.
Question: What is the most efficient/proper way to make Color utilize the operators from Vec? Would making the overloaded operators into template functions solve my problem (how?). Or should I take an entirerly different approach? I look forward to any help I can get, thank you.
Why not just something like this:
#include <cstddef>
template <size_t N>
class Vector {
public:
Vector();
friend Vector operator+(const Vector& lh, const Vector& rh);
//...
private:
double val[N];
};
typedef Vector<3> Vector3d;
typedef Vector<4> Color;