Could use some help...:)

S

Silver

First of all...merry christmas everyone!

Now, I have to write a program. Among other things, I need to overload the
'*' operator, so that it returns a pointer-to-ponter of type int, which is
intended to contain a 2d array.
Now, I have 2 classes, as follows:
class A

{

protected:

int n; // It's the size of a nxn matrix. Is read from the
keyboard in the constructor

int **p; // memory is dynamically allocated so that p can be
used as an nxn array

public:

A() { } // Default constructor

A(int x); // Constructor with argument

~A(); // Destructor

};



class B: public A // INHERITANCE

{

private:

int k; // size for a kxk array. Is read form the keyboard in the
constructor

int **d; // memory is dynamically allocated so that d can be
used as an kxk array

public:

B(int y);

~B();

};

In the constructor definitions, I allocate memory dynamically, plus I read
the values for the array. In the main program, 2 objects are created :

A a;

B b;

What I am supposed to do, is use the overloaded operator in main(), so that
b.d contains the product of a.p * b.p. ( the funny thing is that a.p*b.p is
nxn array while b.d is an kxk array!! )

I am having some difficulties as to where to define the overloaded operator:

---as a member of class A?

---as a member of class B?

---friend perhaps?

cause whatever I try, I keep getting the error that I cannot access some
class member. The last thing I tried was defining accessors in each class
( get_d, get_p etc) which looked very silly. It compiled, but I got a
run-time error :)

Could someone advise me on how to implement the overloading ?

PS. Using VS .NET



Thanks in advance!
 
J

Jeff Schwab

I am having some difficulties as to where to define the overloaded operator:

---as a member of class A?

---as a member of class B?

---friend perhaps?

Implement operator *= as a member of A, and let a global (namespace)
operator call the *= operator of a local object.

cause whatever I try, I keep getting the error that I cannot access some
class member. The last thing I tried was defining accessors in each class
( get_d, get_p etc) which looked very silly. It compiled, but I got a
run-time error :)

It only looks silly to you because you're not accustomed to it. Put the
accessors back, and while you're at it, make all the member data private
(not protected) and make A's destructor virtual. Come to think of it,
why is B a separate class at all? What does it do that A doesn't?

Re-post code that shows the run-time error and someone here will
probably be able to show you what's wrong and how to fix it.

-Jeff
 
J

Jeff Schwab

Jeff said:
Implement operator *= as a member of A, and let a global (namespace)
operator call the *= operator of a local object.




It only looks silly to you because you're not accustomed to it. Put the
accessors back, and while you're at it, make all the member data private
(not protected) and make A's destructor virtual. Come to think of it,
why is B a separate class at all? What does it do that A doesn't?

Re-post code that shows the run-time error and someone here will
probably be able to show you what's wrong and how to fix it.

Oh, and remove useless comments like "Constructor with argument." Those
facts are evident from the code. Your comments have a very low
signal-to-noise ratio.

Just to be clear, no offense is meant by my criticisms. I believe you
will benefit greatly from making sure, as you write each line of code,
that you're writing it for a reason. If you're not sure that a given
line or comment makes your program better, omit it.

(Note to the "all comments are good" clan: useless comments hurt
readability in unspeakable ways. I've been led on far more wild goose
chases by bad comments than I have by bad code.)

-Jeff
 
S

Silver

Just to be clear, no offense is meant by my criticisms. I believe you
will benefit greatly from making sure, as you write each line of code,
that you're writing it for a reason. If you're not sure that a given
line or comment makes your program better, omit it.

That 's the reason I posted my message from the first place, to be given
some advice, of any kind ;)

Here's my code with run-time error. It will look pretty clumsy, I'm still a
beginner after all :eek:
(Indentation will be bad, due to copy-paste)
Plus, I didn't grasp that thing about:
"Implement operator *= as a member of A, and let a global (namespace)
operator call the *= operator of a local object."


#include <iostream>
#include <iomanip>
using namespace std;

class A
{
protected:
int n;
int **p;

public:
A() { }
A(int x);
~A();

int** get_d() const { return p; }
int operator [](unsigned row); // Overloaded 'array-access
operator'
};

// Constructor definition
A::A(int x)
{
n = x;

// dynamic 2D array allocation
p = new int *[n];
if (p == 0)
{
cout << endl
<< "Memory allocation failed.\n";
exit(1); // Terminate program
}
for (int i1 = 0; i1 < n; i1++)
{
p[i1] = new int[n];
if (p[i1] == 0)
{
cout << endl
<< "Memory allocation failed.\n";
exit(1); // Terminate program
}
}

cout << endl;
for (int i2 = 0; i2 < n; i2++)
{
for (int i3 = 0; i3 < n; i3++)
{
cout << "p[" << i2 << "][" << i3 << "] = ";
cin >> p[i2][i3];
}
}
}

A::~A()
{
for (int i = 0; i < n; ++i)
delete[] p;
delete[] p;
}



class B: public A
{
private:
int k;
int **d;

public:
B(int y);
~B();
int operator [](unsigned row); // Overloaded 'array-access
operator'
int operator ()(unsigned row, unsigned column); // Overloaded '()'
operator

friend void setD(A a, B b);
friend int** operator*(const A &alpha, const B &beta);
};

B::B(int y)
{
k = y;

// dynamic 2D array allocation
d = new int *[k];
if (d == 0)
{
cout << endl
<< "Memory allocation failed.\n";
exit(1); // Terminate program
}
for (int i4 = 0; i4 < k; i4++)
{
d[i4] = new int[k];
if (d[i4] == 0)
{
cout << endl
<< "Memory allocation failed.\n";
exit(1);
}
}

cout << endl;
for (int i5 = 0; i5 < k; i5++)
{
for (int i6 = 0; i6 < k; i6++)
{
cout << "d[" << i5 << "][" << i6 << "] = ";
cin >> d[i5][i6];
}
}
}

B::~B()
{
for (int i = 0; i < n; ++i)
delete[] d;
delete[] d;
}

int B::eek:perator [](unsigned row)
{
int row_sum = 0;
for (int j = 0; j < n; j++)
row_sum += row_sum + d[row][j];
return row_sum;
}

int B::eek:perator ()(unsigned row, unsigned column)
{
int dot_product = 0;
for (int i = 0; i < n; i++)
dot_product += dot_product + ( p[row] * d[column]);
return dot_product;
}

int A::eek:perator [](unsigned row)
{
int row_sum = 0;
for (int j = 0; j < n; j++)
row_sum += row_sum + p[row][j];
return row_sum;
}

int** operator*(const A &alpha, const B &beta)
{
/*// --- Memory allocation for p_array (nxn) ---
int **p_array = new int *[n];
if (p_array == 0)
{
cout << endl
<< "Memory allocation failed.\n";
exit(1); // Terminate program
}
for (int i = 0; i < n; i++)
{
p_array = new int[n];
if (p_array == 0)
{
cout << endl
<< "Memory allocation failed.\n";
exit(1);
}
}
// --- End of memory allocation ---

/* Problem encountered:
** int (*p_array )[n] = new const int[n][n];
** Error message. ???
*/

// Matrix multiplication
int **temp = alpha.get_d();

cout << endl;
for(int j1 = 0; j1 < beta.n; j1++)
{
for (int j2 = 0 ; j2 < beta.n; j2++)
{
beta.d[j1][j2] = 0;
for(int j3 = 0; j3 < beta.k; j3++)
{
beta.d[j1][j2] += temp[j1][j3] * beta.p[j3][j2];
}
cout << setw(4) << beta.d[j1][j2];
}
cout << endl;
}
return beta.d;
}


//void setD(A a, B b)
//{
// b.d = (a.p)*(b.p);
//}



int main()
{
int size;

cout << "\nDwse diastash n gia ton pinaka nxn? --> ";
cin >> size;

A a(size);
B b(size);
//b.pa*b;


cout << endl;
return 0;
}
 
S

Silver

One more thing. I read that it's a good practise to use the keyword const
"wherever is possible". How much true is that? I have the feeling that I 'm
not using it in the right way.
 
J

Jeff Schwab

Silver said:
That 's the reason I posted my message from the first place, to be given
some advice, of any kind ;)

Here's my code with run-time error. It will look pretty clumsy, I'm still a
beginner after all :eek:
(Indentation will be bad, due to copy-paste)
Plus, I didn't grasp that thing about:
"Implement operator *= as a member of A, and let a global (namespace)
operator call the *= operator of a local object."

Don't worry, you're doing fine. :)

Quick question: What type of product is a * b supposed to give? Is
that a cross product? I will be grateful if you clarify.
One more thing. I read that it's a good practise to use the keyword
const "wherever is possible". How much true is that? I have the
feeling that I 'm not using it in the right way.

Don't worry about it. Some folks believe (mistakenly) that "const"
enables certain compiler optimizations. It does nothing of the kind,
since casts can override const. The const keyword is primarily useful
for three purposes:

1) As a promise to the caller of a function that you will not change an
argument that has been passed by reference.

2) To cause a compile-time error when an object is used in an
inappropriate way.

3) To let a method of a const object be called.

Hth,
Jeff
 
S

Silver

It's the cross product. I forget to mention it!
(The program doesn't actually do something useful. It's only an exercise
given to me. )

Thx!
 
J

Jeff Schwab

Silver said:
It's the cross product. I forget to mention it!
(The program doesn't actually do something useful. It's only an exercise
given to me. )

Thx!

Here's what I think you wanted. This implementation is naive; it does
not check for I/O stream failures, integer oveflow, etc. I replaced
class A with Matrix, since "A" isn't particularly meaningful. :) I got
rid of B altogether (not sure what purpose it served), and replaced your
dynamically allocated array of dynamically allocated arrays with a
vector of vectors. (In my own code, I typically use only one vector for
all elements, and access element i,j of matrix A_m,n as vector[ i * n +
j ]. Some folks prefer to use standard valarrays and slices. )

I noticed that in your code, your response to errors was to exit the
program, wherever you happened to be. I've replaced this technique with
some basic, exception-based error-handling, just to give you the idea.
Exceptions are usually better, mainly because the appropriate
destructors can be called. For example, if an exception is thrown in
this program, the vectors used to store the matrix will have a chance to
free the memory they've been allocated. In your original code, the
dynamically allocated memory would not be freed, and may or may not have
been reclaimed, depending on the OS where the program was run.

I understand that this is just an exercise; that's great. For me, at
least, writing and reading code is essential to improving. If you
actually needed matrix cross products for a "real" program, though, you
wouldn't need to write them yourself. There are plenty of well-tested,
efficient matrix libraries available. Google for details.

Hth,
Jeff

#include <iostream>
#include <iomanip>
#include <new>
#include <vector>

namespace Silver
{
/* Represents a matrix of m rows and n columns.
*/
class Matrix
{
public:
typedef std::vector< int > Row;
typedef std::vector< Row > Row_Vector;

Matrix( int m =0, int n =0 );

Row& operator [ ] ( int row );
Row const& operator [ ] ( int row ) const;

Matrix const& operator *= ( Matrix const& other );

int m( ) const;
int n( ) const;

void resize( int m, int n );

private:

Row_Vector m_rows;
};

// Outer (cross) product.
Matrix const operator * ( Matrix const&, Matrix const& );

std::eek:stream& operator << ( std::eek:stream&, Matrix const& );
}

int Silver::Matrix::m( ) const
{
return m_rows.size( );
}

int Silver::Matrix::n( ) const
{
return m_rows.front( ).size( );
}

Silver::Matrix::Row&
Silver::Matrix::eek:perator [ ] ( int row )
{
return m_rows[ row ];
}

Silver::Matrix::Row const&
Silver::Matrix::eek:perator [ ] ( int row ) const
{
return m_rows[ row ];
}

Silver::Matrix const&
Silver::Matrix::eek:perator *= ( Silver::Matrix const& other )
{
return *this = *this * other;
}

Silver::Matrix::Matrix( int m, int n )
try
{
resize( m, n );
}
catch( std::bad_alloc x )
{
throw std::string( "Silver::Matrix::Matrix( int n ): "
"Not enough memory is available." );
}
catch( std::string s )
{
throw std::string( "Silver::Matrix::Matrix( int n ): " ) + s;
}
catch( ... )
{
throw std::string( "Silver::Matrix::Matrix::( int n ): "
"unexpected exception" );
}

void Silver::Matrix::resize( int new_m, int new_n )
try
{
if( new_m < 0 or new_n < 0 )
{
throw std::string( "matrix dimensions cannot be negative" );
}

Row_Vector new_rows = m_rows;

new_rows.resize( new_m );

for( int row = 0; row < new_m; ++row )
{
new_rows[ row ].resize( new_n );
}

m_rows.swap( new_rows );
}
catch( std::bad_alloc x )
{
throw std::string( "Silver::Matrix::resize( int m, int n ): "
"Not enough memory is available." );
}
catch( std::string s )
{
throw std::string( "Silver::Matrix::resize( int m, int n ): " )
+ s;
}
catch( ... )
{
throw std::string( "Silver::Matrix::resize( int m, int n ): "
"unexpected exception" );
}

Silver::Matrix const
Silver::eek:perator * ( Silver::Matrix const& a, Silver::Matrix const& b )
try
{
if( a.n( ) != b.m( ) )
{
throw std::string(
"arguments are not conformable for multiplication" );
}

Matrix result( a.m( ), b.n( ) );

for( int row = 0; row < a.m( ); ++row )
{
for( int column = 0; column < b.n( ); ++column )
{
for( int i = 0; i < a.n( ); ++i )
{
result[ row ][ column ] +=
a[ row ][ i ] * b[ i ][ column ];
}
}
}

return result;
}
catch( std::string s )
{
throw std::string( "Silver::eek:perator * ( "
"Silver::Matrix const&, "
"Silver::Matrix const& ): " ) + s;
}
catch( ... )
{
throw std::string( "Silver::eek:perator * ( "
"Silver::Matrix const&, "
"Silver::Matrix const& ): "
"unexpected exception" );
}

std::eek:stream&
Silver::eek:perator << ( std::eek:stream& out, Silver::Matrix const& matrix )
{
for( int row = 0; row < matrix.m( ); ++row )
{
out << "[ ";

for( int column = 0; column < matrix.n( ); ++column )
{
out << std::setw( 4 ) << matrix[ row ][ column ] << ' ';
}

out << " ]\n";
}

return out;
}

namespace
{
/* Prompt for values, then populate and display the matrix.
*/
void initialize( Silver::Matrix& matrix, std::string const& name )
{
for( int row = 0; row < matrix.m( ); ++row )
{
for( int column = 0; column < matrix.n( ); ++column )
{
/*
std::cout << name << "[ "
<< row << " ][ "
<< column << " ] = "
<< std::flush;
*/

std::cin >> matrix[ row ][ column ];
}
}

std::cout << name << ":\n" << matrix;
}
}

int main( )
try
{
/*
std::cout << "\nDwse diastash n gia ton pinaka nxn? --> "
<< std::flush;
int size;

std::cin >> size;
*/

int am;
int an;
int bm;
int bn;

std::cout << "Enter a.m, a.n, b.m, and b.n.\n";

std::cin >> am >> an >> bm >> bn;

Silver::Matrix a( am, an );
Silver::Matrix b( bm, bn );

initialize( a, "a" );
initialize( b, "b" );

std::cout << "a * b:\n" << ( a * b ) << '\n';
}
catch( std::string s )
{
std::clog << "error: " << s << '\n';
}
catch( ... )
{
std::clog << "error: unexpected exception\n";
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top