How to Overload Operators with Polymorphism

I have to create a Complex class and a vector class that includes vectors of Complex numbers. I have to overload +,-,/,*, << in both classes. Would they both be member functions or would it be easier to put them as nonmember functions? In addition, is there a way to make the vector class only have the vector as a parameter, rather than including the real and imaginary number and vector? The following code from is my class member functions of the vector class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class ComplexVector : public Complex //vectors whose elements are complex numbers
{
public:
  ComplexVector(); 
  ComplexVector(double real, double imaginary, std::vector <Complex> vec); 
  ComplexVector(std::vector <Complex> vec); 
  friend ComplexVector operator+ (const ComplexVector& v1, const ComplexVector& v2);
  friend ComplexVector operator- (const ComplexVector& v1, const ComplexVector& v2);
  friend ComplexVector operator* (const ComplexVector& v1, const ComplexVector& v2);
  friend ComplexVector operator/ (const ComplexVector& v1, const ComplexVector& v2);
  int get_size() const; 

private:
  std::vector <Complex> cvec;

};
std::ostream& operator<< (std::ostream& stream, const ComplexVector& comvec); 


I put the explanations of each function in a separate cpp file. Even though I used friend in the header file, on the cpp file it says that i am not allowed to use two parameters. Is there a way to get out of that? In addition, would I have to use pointers in order to access what is in the vector? I have heard of using vector but I have tried and the arithmetic doesn't make sense to me. (Note: I was playing around so not all the code is exactly correct) Thanks!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
ComplexVector::ComplexVector() : Complex() {}
ComplexVector::ComplexVector(double real, double imaginary, std::vector<Complex> vec) : Complex(real, imaginary), cvec(vec) {}
ComplexVector::ComplexVector(std::vector<Complex>vec) {cvec = vec;}
ComplexVector& ComplexVector::operator+ (ComplexVector v1, const ComplexVector& v2)
{
  std::vector <Complex> add;
  for (int i = 0; i < v1.get_size(); i++)
  {
    double xside = v1[i].get_real() + v2[i].get_real();
    double yside = v1[i].get_()imaginary + v2[i].get_imaginary();
    add[i] = Complex(xside,yside);
  }
  ComplexVector add_sol(add);
  return add_sol;
}
ComplexVector ComplexVector::operator- (const ComplexVector& v1, const ComplexVector& v2)
{
  std::vector <Complex> sub;
  for (int i= 0; i < v1.get_size(); i++)
  {
    sub[i] = v1[i] - v2[i]; //same as +?
    //does not provide subscript operator????
  }
  ComplexVector sub_sol(sub);
  return sub_sol;
}
ComplexVector ComplexVector::operator* (const ComplexVector& v2)
{
  ComplexVector multi;
  for (int i = 0; i < v1.size(); i++)
  {
    multi[i] = v1[i] * v2[i];
  }
  return multi;
}
ComplexVector operator/ (const ComplexVector& v2)
{
  ComplexVector div;
  for (int i = 0; i < v1.size(); i++)
  {
    div[i] = v1[i] / v2[i];
  }
  return div;
}
int ComplexVector::get_size() const
{
  int total;
  for (int i = 0, i < cvec.size(); i++)
  {
    total++;
  }
 return total;
}
std::ostream& ComplexVector::operator<< (std::ostream& stream, const ComplexVector& comvec)
{
  for (int i = 0; i < comvec.size(); i++)
  {
    stream << comvec[i] -> get_real() << " " << "+" << " " << comvec[i] -> get_imaginary() << "i" ;
  }
  return stream;
}
Last edited on
> class ComplexVector : public Complex
¿are you sure about that inheritance?
¿what are you doing with the `real' and `imaginary' members that were inherit from `Complex?


> friend ComplexVector operator+ (const ComplexVector& v1, const ComplexVector& v2);
there you are declaring a non-member function

> ComplexVector& ComplexVector::operator+ (ComplexVector v1, const ComplexVector& v2)
there you are defining a member function.
that's why it's complaining about «not allowed to use two parameters» (remember that being a member function you also have this)

Also, note that you are changing the prototype. You are returning a reference (to a local variable even) and passing the first parameter by copy instead of const reference.


> Would they both be member functions or would it be easier to put them as
> nonmember functions?
overload +=, -=, /=, *=, as member functions
define +, -, /, *, as non-friend non-member function
1
2
3
ComplexVector operator+(ComplexVector a, const ComplexVector &b){
	return a += b;
}


For <<, notice that the left side is not your class, but ostream
so you can't make it a member function (as you don't have access to ostream code)
if you need it to be friend or not, would depend on the interface of your class.


> would I have to use pointers in order to access what is in the vector? I have
> heard of using vector but I have tried and the arithmetic doesn't make sense
> to me
sorry, not follow.
focus on just one operator and make your code compilable, then show your issue.
Also, show your `Complex' class.
I took off the inheritance of Complex in ComplexVector.
I must have missed the small part in my question. Would I have to use pointers in order to access what is in the vector. I have heard of using std::vector<Complex*> but I have tried and the arithmetic doesn't make sense.

Do I keep the operator overload functions in the class?

This is the header file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Complex //Complex numbers are expressed in the form a + bi, where a is the real part, b is the imaginary part, and i is the imaginary unit satisfying i2 = -1.
{
public:
    Complex(); 
    Complex (double r, double i); 
    Complex operator+ (const Complex& c2); 
    Complex operator- (const Complex& c2);
    Complex operator* (const Complex& c2);
    Complex operator/ (const Complex& c2);
    double get_real() const; //declared
    double get_imaginary() const; //declared
    
private:
    double real;
    double imaginary;
    
};
std::ostream& operator<< (std::ostream& stream, const Complex& comvec); 

class ComplexVector //vectors whose elements are complex numbers
{
public:
    ComplexVector();
    ComplexVector(std::vector <Complex*> vec); 
    friend ComplexVector operator+ (ComplexVector v1, const ComplexVector& v2);
    friend ComplexVector operator- (ComplexVector v1, const ComplexVector& v2);
    friend ComplexVector operator* (ComplexVector v1, const ComplexVector& v2);
    friend ComplexVector operator/ (ComplexVector v1, const ComplexVector& v2);
    int get_size() const; 
    
private:
    std::vector <Complex*> cvec;
    
};
std::ostream& operator<< (std::ostream& stream, const ComplexVector& comvec);


I changed the cpp file as well. I keep getting the notification of "Type 'ComplexVector' does not provide a subscript operator" and "Type 'const ComplexVector' does not provide a subscript operator". I thought i was able to use [] because I am going through a vector.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
ComplexVector::ComplexVector() {}
ComplexVector::ComplexVector(std::vector<Complex*> vec) {cvec = vec;}
ComplexVector operator+ (ComplexVector v1, const ComplexVector& v2)
{
    std::vector <Complex*> add;
    for (int i = 0; i < v1.get_size(); i++)
    {
        double xside = v1(i).get_real() + v2[i].get_real();
        double yside = v1[i].get_imaginary() + v2[i].get_imaginary();
        add[i] = new Complex(xside,yside);
    }
    ComplexVector add_sol(add);
    return add_sol;
}
ComplexVector operator- (ComplexVector v1, const ComplexVector& v2)
{
    std::vector <Complex*> sub;
    for (int i= 0; i < v1.get_size(); i++)
    {
        double xside = v1[i].get_real() - v2[i].get_real();
        double yside = v1[i].get_real() - v2[i].get_real();
        sub[i] = new Complex(xside,yside);
        //does not provide subscript operator????
    }
    ComplexVector sub_sol(sub);
    return sub_sol;
}
ComplexVector operator* (ComplexVector v1, const ComplexVector& v2)
{
    std::vector <Complex*> multi;
    for (int i = 0; i < v1.get_size(); i++)
    {
        double xside = (v1[i].get_real() * v2[i].get_real) - (v1[i].get_imaginary() * v1[i].get_imaginary);
        double yside = (v1[i].get_real() * v2[i].geT_imaginary) + (v2[i].get_real * v1[i].get_imaginary;
        multi[i] = new Complex(xside, yside);
    }
    ComplexVector multi_sol(multi);
    return multi_sol;
}
ComplexVector operator/ (const ComplexVector& v2)
{
    std::vector<Complex*> div;
    for (int i = 0; i < v1.get_size(); i++)
    {
        double xside = ((v1[i].get_real() * v1[i].get_imaginary()) + (v1[i].get_imaginary() * v2[i].get_imaginary())) / ((v2[i].get_real() * v2[i].get_real()) + (v2[i].get_imaginary * v2[i].get_imaginary())));
        double yside = ((v1[i].get_imaginary() * v2[i].get_real()) - (v1[i].get_real() * v2[i].get_imaginary())/ (v2[i].get_real() * v2[i].get_real() + (v2[i].get_imaginary() * v2[i].get_imaginary())));
        div[i] = new Complex(xside, yside);
    }
    ComplexVector div_sol(div);
    return div;
}

int ComplexVector::get_size() const
{
    int total;
    for (int i = 0, i < cvec.size(); i++)
    {
        total++;
    }
    return total;
}
//ComplexVector nonmember
std::ostream& ComplexVector::operator<< (std::ostream& stream, const ComplexVector& comvec)
{
    for (int i = 0; i < comvec.size(); i++)
    {
        stream << comvec[i] -> get_real() << " " << "+" << " " << comvec[i] -> get_imaginary() << "i" ;
    }
    return stream;
}
> std::vector<Complex*>
don't do that, there is no benefit over std::vector<Complex>
you are simply increasing the complexity of your program, as now you've got to do memory management.


> I thought i was able to use [] because I am going through a vector.
`cvec' is a vector, you can use [] on `cvec'
1
2
3
4
5
6
ComplexVector& ComplexVector::operator+= (const ComplexVector& v2){
   for (int K = 0; K < this->cvec.size(); K++)
      this->cvec[K] += v2.cvec[K]; //using the operator+= of `Complex'

   return *this;
}

notice that I've defined operator+=, and that used the operator+= of Complex (you don't have it, you have operator+)

perhaps you do want the client code to use [] on your ComplexVector, then you need to provide that member function (both const and nonconst versions)
1
2
3
4
5
6
7
Complex& ComplexVector::operator[](int index){ //as a member function
   return this->cvec[index];
}

const Complex& ComplexVector::operator[](int index) const{ //to work with const objects
   return this->cvec[index];
}



By the way, if a member function does not modify the state of its object, declare it const so it can work with constant objects
Complex operator+ (const Complex& c2) const;
> I have to overload +,-,/,*, << in both classes.
> Would they both be member functions or would it be easier to put them as nonmember functions?

Canonical implementations
Commonly overloaded operators have the following typical, canonical forms:

Stream extraction and insertion
The overloads of operator>> and operator<< that take a std::istream& or std::ostream& as the left hand argument are known as insertion and extraction operators. Since they take the user-defined type as the right argument (b in a@b), they must be implemented as non-members.

Binary arithmetic operators
Binary operators are typically implemented as non-members to maintain symmetry (for example, when adding a complex number and an integer, if operator+ is a member function of the complex type, then only complex+integer would compile, and not integer+complex). Since for every binary arithmetic operator there exists a corresponding compound assignment operator, canonical forms of binary operators are implemented in terms of their compound assignments.
http://en.cppreference.com/w/cpp/language/operators


For example, using std::complex<double> (instead of a custom complex class) for brevity:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <iostream>
#include <complex>
#include <vector>

using complex = std::complex<double> ;

struct complex_vector : private std::vector<complex>
{
    using std::vector<complex>::vector ;
    using std::vector<complex>::operator= ;
    using std::vector<complex>::size ;
    using std::vector<complex>::empty ;
    // etc.

    // implement overloaded compound assignment operators (member functions)
    complex_vector& operator+= ( const complex_vector& that ) {

        resize( std::max( size(), that.size() ) ) ;
        for( std::size_t i = 0 ; i < that.size() ; ++i ) (*this)[i] += that[i] ;
        return *this ;
    }
    // likewise for -=, *=, /=
    complex_vector& operator-= ( const complex_vector& that ) ;
    complex_vector& operator*= ( const complex_vector& that ) ;
    complex_vector& operator/= ( const complex_vector& that ) ;

    // implement overloaded arithmetic operators in terms of the corresponding
    // compond assignment operator. note that the first argument is passed by value
    // this is canonical. see Canonical implementations: Binary arithmetic operators
    // in http://en.cppreference.com/w/cpp/language/operators
    friend complex_vector operator+ ( complex_vector a, const complex_vector& b ) { return a += b ; }
    friend complex_vector operator- ( complex_vector a, const complex_vector& b ) { return a -= b ; }
    friend complex_vector operator/ ( complex_vector a, const complex_vector& b ) { return a /= b ; }
    friend complex_vector operator* ( complex_vector a, const complex_vector& b ) { return a *= b ; }

    // overloaded stream insertion operator can't be a member function
    friend std::ostream& operator<< ( std::ostream& stm, const complex_vector& vec ) {

        stm << "[ " ;
        for( const complex& c : vec ) stm << c << ' ' ;
        return stm << ']' ;
    }
};

int main() {

    const complex_vector a( 6, complex{ 1.01, 2.34 } ) ;
    const complex_vector b { {1.12,2.23}, {3.34, 4.45}, {5.56,6.67} } ;

    std::cout << a << " +\n" << b << " ==\n" << a+b << '\n' ;
}

http://coliru.stacked-crooked.com/a/3cbaa87a9802c3e7
Topic archived. No new replies allowed.