Inherited operators

Hey all, here is the problem:
I'm built a Matrix class and I did the dirty work redefining all the boring operators (+,-,* etc.). Now I needed a specifical Vector class, so I decided to let it inherit from Matrix class (as vectors, for the most, should act like n x 1 or 1 x n matrices). So i have, for example, a Matrix operator+ function working this way

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
VMatrix VMatrix::operator+ (const VMatrix &add)
{
	if (rows() == add.rows() && cols() == add.cols())
	{
		VMatrix r(rows(),cols());

		for(int i=0;i<rows();i++)
		{
			for (int j=0;j<cols();j++)
			{
				r[i][j] = m[i][j] + add[i][j];
			}
		}
		return r;
	}
	cout << "Bad operation."<<endl;
	return VMatrix();
}


it obviously does the sum of the two matrices and returns a Matrix element. Now if my Vector class inherits this method is awesome but there is a problem: the sum of two vectors will return a Matrix not a Vector!
This makes lines of code like this

(v1+v2).inline_print() //function implemented *just* in Vector class

uncompilable. And i saw some strange errors like, for example, vectors divided by some constant becoming 0. Is there a clean way to let the Vector class inherit the same operators but with function returning the correct class type? Redefining all operators would make inheriting useless.

Thanks in advance, valleyman
You have to make sure that a few conditions are met.
Make your operators friend functions, and make sure you have the proper constructors and the like.

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
#include <iostream>
using namespace std;

struct point_t
  {
  int x, y;
  point_t( int x = 0, int y = 0 ): x( x ), y( y ) { }
  point_t( const point_t& pt ): x( pt.x ), y( pt.y ) { }
  friend point_t operator + ( const point_t& lhs, const point_t& rhs );
  };

point_t operator + ( const point_t& lhs, const point_t& rhs )
  {
  return point_t( lhs.x + rhs.x, lhs.y + rhs.y );
  }

ostream& operator << ( ostream& outs, const point_t& pt )
  {
  return outs << "(" << pt.x << "," << pt.y << ")";
  }

int gcd( int a, int b )
  {
  if (a == 0)
    return b;

  while (b != 0)
    {
    if (a > b) a -= b;
    else       b -= a;
    }

  return a;
  }

struct coprime_t: public point_t
  {
  coprime_t( int x, int y ): point_t( x, y ) { }
  coprime_t( const point_t& pt ): point_t( pt ) { }
  bool valid() const
    {
    return gcd( x, y ) == 1;
    }
  };

int main()
  {
  coprime_t a( 6, 9 );
  coprime_t b( 0, 4 );
  coprime_t c = a + b;

  cout << a << " is " << (a.valid() ? "coprime\n" : "not coprime\n");
  cout << b << " is " << (b.valid() ? "coprime\n" : "not coprime\n");
  cout << c << " is " << (c.valid() ? "coprime\n" : "not coprime\n");

  return 0;
  }

Good luck!
Well I defined them correctly - I think - because the above code approximately works.
But instead of

coprime_t c = a + b;

I'd like to be able to use concatenated operators like below

(a + b).coprime_print() // with coprime_print() being a coprime_t specific function

Do I have to redefine all the operators?
Thanks for the help
Last edited on
I don't see why that wouldn't work... actually now that I read the definitions a bit closer, yes I do.

-Albatross
Last edited on
Yes, you would have to update the operators, because default type promotion needs to work. There is no default type promotion to figure out what class is meant when you simply add two.

JSYK, using constructs like (a + b).quux() is not a good idea. Be explicit:

1
2
3
4
5
6
foo( a + b ).quux();
//or
{
  foo x = a + b;
  x.quux();
}

Good luck!

@Albratross:

I don't see why that wouldn't work...

Well it wouldn't because (a+b) returns a point_t object - not coprime_t - and there is no function coprime_print() defined in the point_t class.

@Duoas: I understood, thanks for the very clear explanation. Just a question, for the sake of curiosity,

JSYK, using constructs like (a + b).quux() is not a good idea. Be explicit:


why isn't it a good idea? Just because it brings the above problem or for any other reasons?
Yes, for the very reasons we have covered, plus it just looks fugly to use a temporary object that way.
Plus when you compile your code in release mode the temporary vars disappear (most of the time).
Optimizations are not permitted to change the behavior of the program. When they do, that's a bug in the optimizer.
Indeed, thanks for the help guys!
Topic archived. No new replies allowed.