473,796 Members | 2,550 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Operator [][]?

I am trying to make a 2D matrix class. The data in the matrix will be of
type int and so the underlying data structure will be a 2D array (int **
matrix). To make the data easy to modify, I would like to be able to
modify this private array in the class with the operator [][]. I know
that the operator[] can be overloaded. However, is there away to overload
[][]?

Thanks,
Michael
Oct 16 '06 #1
6 1681
* Michael DeWulf:
I am trying to make a 2D matrix class. The data in the matrix will be of
type int and so the underlying data structure will be a 2D array (int **
matrix). To make the data easy to modify, I would like to be able to
modify this private array in the class with the operator [][]. I know
that the operator[] can be overloaded. However, is there away to overload
[][]?
Not directly, but it can be done by letting operator[] return a proxy
object, or letting it return a pointer or a reference to something
indexable.

However, the proxy idea generally means reduced performance, and the
pointer and reference ideas expose the implementation so it can't be
changed (and a pointer to a raw array is very unsafe).

For more about the latter point, and how you should be doing this
(namely, using operator()), see the FAQ item titled "Why shouldn't my
Matrix class's interface look like an array-of-array?", currently at
<url:
http://www.parashift.c om/c++-faq-lite/operator-overloading.htm l#faq-13.11>.

Btw., it's always a good idea to look in the FAQ before posting.

And do consider using a std::vector as the representation, rather than a
raw pointer to dynamically allocated array.

It's more safe and yields less code and more clear code.

Hth.,

- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Oct 16 '06 #2
Alf P. Steinbach wrote:
* Michael DeWulf:
>I am trying to make a 2D matrix class.
To the OP: don't---use one of those that are around.
>The data in the matrix will be of
type int and so the underlying data structure will be a 2D array (int **
matrix). To make the data easy to modify, I would like to be able to
modify this private array in the class with the operator [][]. I know
that the operator[] can be overloaded. However, is there away to
overload
[][]?

Not directly, but it can be done by letting operator[] return a proxy
object, or letting it return a pointer or a reference to something
indexable.

However, the proxy idea generally means reduced performance,
Do you have actual data to back up that theory? I just whipped up the
following quickly:

#include <vector>
#include <algorithm>

class Matrix {

typedef std::vector<dou blearray;

public:

typedef array::size_typ e size_type;

private:

array the_data;
size_type num_rows;
size_type num_cols;

struct EntryProxy;
struct ConstEntryProxy ;
friend class EntryProxy;
friend class ConstEntryProxy ;

struct EntryProxy {

Matrix & ref;
size_type row;

EntryProxy ( Matrix & m, size_type r )
: ref ( m )
, row ( r )
{}

double & operator[] ( size_type col ) {
return ( ref.the_data[ row * ref.num_cols + col ] );
}

};

struct ConstEntryProxy {

Matrix const & ref;
size_type row;

ConstEntryProxy ( Matrix const & m, size_type r )
: ref ( m )
, row ( r )
{}

double const & operator[] ( size_type col ) const {
return ( ref.the_data[ row * ref.num_cols + col ] );
}

};

public:

Matrix ( size_type n_rows = 0, size_type n_cols = 0 )
: the_data ()
, num_rows ( n_rows )
, num_cols ( n_cols )
{
the_data.resize ( num_rows * num_cols );
}

void swap ( Matrix & other ) {
std::swap( this->the_data, other.the_data );
std::swap( this->num_rows, other.num_rows );
std::swap( this->num_cols, other.num_cols );
}

double & operator() ( size_type row, size_type col ) {
return ( the_data[ row*num_cols + col ] );
}

double const & operator() ( size_type row, size_type col ) const {
return ( the_data[ row*num_cols + col ] );
}

EntryProxy operator[] ( size_type row ) {
return ( EntryProxy( *this, row ) );
}

ConstEntryProxy operator[] ( size_type row ) const {
return ( ConstEntryProxy ( *this, row ) );
}

size_type rows ( void ) const {
return ( num_rows );
}

size_type cols ( void ) const {
return ( num_cols );
}

};
void multiply_no_pro xy ( Matrix const & A,
Matrix const & B,
Matrix & result ) {
Matrix dummy ( A.rows(), B.cols() );
for ( Matrix::size_ty pe r = 0; r < dummy.rows(); ++r ) {
for ( Matrix::size_ty pe c = 0; c < dummy.cols(); ++c ) {
double inner_prod = 0;
for ( Matrix::size_ty pe k = 0; k < A.cols(); ++k ) {
inner_prod += A(r,k)*B(k,c);
}
dummy( r, c ) = inner_prod;
}
}
result.swap( dummy );
}

void multiply_proxy ( Matrix const & A,
Matrix const & B,
Matrix & result ) {
Matrix dummy ( A.rows(), B.cols() );
for ( Matrix::size_ty pe r = 0; r < dummy.rows(); ++r ) {
for ( Matrix::size_ty pe c = 0; c < dummy.cols(); ++c ) {
double inner_prod = 0;
for ( Matrix::size_ty pe k = 0; k < A.cols(); ++k ) {
inner_prod += A[r][k]*B[k][c];
}
dummy[r][c] = inner_prod;
}
}
result.swap( dummy );
}

#include <iostream>

int main ( void ) {
Matrix A ( 200, 3000 );
Matrix B ( 3000, 200 );
Matrix C;
#ifdef USE_PROXY
multiply_proxy( A, B, C );
std::cout << "used proxy " << C(2,2);
#else
multiply_no_pro xy( A, B, C );
std::cout << "did not use proxy " << C(2,2);
#endif
std::cout << '\n';
}

I got:

news_groupcc++ -O3 -DUSE_PROXY alf_008.cc
news_grouptime a.out
used proxy 0

real 0m2.374s
user 0m1.540s
sys 0m0.076s
news_grouptime a.out
used proxy 0

real 0m3.151s
user 0m1.920s
sys 0m0.088s
news_grouptime a.out
used proxy 0

real 0m3.137s
user 0m1.936s
sys 0m0.116s
news_grouptime a.out
used proxy 0

real 0m2.723s
user 0m1.756s
sys 0m0.076s

news_groupcc++ -O3 alf_008.cc
news_grouptime a.out
did not use proxy 0

real 0m2.343s
user 0m1.564s
sys 0m0.056s
news_grouptime a.out
did not use proxy 0

real 0m2.474s
user 0m1.584s
sys 0m0.064s
news_grouptime a.out
did not use proxy 0

real 0m2.924s
user 0m1.856s
sys 0m0.084s
news_grouptime a.out
did not use proxy 0

real 0m3.166s
user 0m1.812s
sys 0m0.096s
Doesn't look like a significant difference to me. I wouldn't be surprised if
a compiler would generate identical code for both programs.

and the
pointer and reference ideas expose the implementation so it can't be
changed (and a pointer to a raw array is very unsafe).
Agreed.

For more about the latter point, and how you should be doing this
(namely, using operator()), see the FAQ item titled "Why shouldn't my
Matrix class's interface look like an array-of-array?", currently at
<url:
http://www.parashift.c om/c++-faq-lite/operator-overloading.htm l#faq-13.11>.
>
Btw., it's always a good idea to look in the FAQ before posting.
This particular point of the FAQ is highly contested: The interface design
suggested by the FAQ may make sense from the point of view of the
implementer. However, libraries are to be designed from the point of view
of the user. In that case, you want to have proxies for rows and columns
anyway so that you could do, e.g., row-operations like so:

A.row(i) += some_scalar* A.row(j);

Of course, such proxies require some amount of magic. A good matrix
interface is not for the faint of heart.

And do consider using a std::vector as the representation, rather than a
raw pointer to dynamically allocated array.

It's more safe and yields less code and more clear code.
I took the liberty to illustrate that in the code.
Best

Kai-Uwe Bux

Oct 16 '06 #3
* Kai-Uwe Bux:
Alf P. Steinbach wrote:
>>
However, the proxy idea generally means reduced performance,

Do you have actual data to back up that theory?
Nope, just hearsay (although from competent folks), the expectation that
added code and longer call chains means reduced performence, and my own
experience /many/ years ago -- it was probably with Turbo C++...

I just whipped up the following quickly:
[example showing no significant performance difference, snipped]

I stand (or actually, to be honest, sit) corrected -- thanks.

news_groupcc++ -O3 -DUSE_PROXY alf_008.cc
I only have one program from you that I've tested, and you've already
reached number 8 on me! :-o)

Cheers,

- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Oct 16 '06 #4
Kai-Uwe Bux wrote:
Alf P. Steinbach wrote:
....
>>
http://www.parashift.c om/c++-faq-lite/operator-overloading.htm l#faq-13.11>.
>Btw., it's always a good idea to look in the FAQ before posting.

This particular point of the FAQ is highly contested:...
Just want to add my $0.02 worth. I agree with you. I think we had this
discussion 6 months ago. Maybe it is time to get the FAQ changed.

G
Oct 16 '06 #5

Michael DeWulf wrote:
I am trying to make a 2D matrix class. The data in the matrix will be of
type int and so the underlying data structure will be a 2D array (int **
matrix). To make the data easy to modify, I would like to be able to
modify this private array in the class with the operator [][]. I know
that the operator[] can be overloaded. However, is there away to overload
[][]?
No, but [,] is "overloadab le":

By Jack Saalweachter

struct MagicInt {
// operator overloads, constructors, etc, to make this class behave
// as an integer.

};

std::pair<Magic Int, MagicIntoperato r , (const MagicInt &a, const
MagicInt& b) { return std::make_pair( a, b); }

class Array2d {
public:
value& operator[](const std::pair<Magic Int, MagicInt&a) {
// use a.first and a.second to find the value...
}

};

int main() {
Array2d M(X, Y);

for (MagicInt a = 0; a < X; ++a)
for (MagicInt b = 0; b < Y; ++b)
M[a, b] = i + j;

}

Of course, overloading (,) works better and is a lot easier.

Oct 17 '06 #6

Gianni Mariani wrote:
Kai-Uwe Bux wrote:
Alf P. Steinbach wrote:
...
>
http://www.parashift.c om/c++-faq-lite/operator-overloading.htm l#faq-13.11>.
Btw., it's always a good idea to look in the FAQ before posting.
This particular point of the FAQ is highly contested:...

Just want to add my $0.02 worth. I agree with you. I think we had this
discussion 6 months ago. Maybe it is time to get the FAQ changed.

G
My matrix template allows both notations. operator[] returns a row and
from the row you can also use operator[] to get an element. operator()
gets the element directly.

The row is of a buffer type that I use throughout my code that is
effectively a weak pointer and a size. It also has begin() and end()
methods that return pointers and can be used in algorithms. It has
several constructors including an implicit one from vector and it does
not take ownership of its pointer. There are two versions, one for
const and one for non-const and the const one has an implicit
constructor from the non-const one.

Oct 17 '06 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

7
8034
by: Paul Davis | last post by:
I'd like to overload 'comma' to define a concatenation operator for integer-like classes. I've got some first ideas, but I'd appreciate a sanity check. The concatenation operator needs to so something like this: 1) e = (a, b, c, d); // concatenate a,b,c,d into e 2) (a, b, c, d) = e; // get the bits of e into a,b,c, and d For example, in the second case, assume that a,b,c,d represent 2-bit integers, and e represents an 8-bit...
1
3880
by: joesoap | last post by:
Hi can anybody please tell me what is wrong with my ostream operator??? this is the output i get using the 3 attached files. this is the output after i run assignment2 -joesoap #include "BitString.h"
5
3808
by: Jason | last post by:
Hello. I am trying to learn how operator overloading works so I wrote a simple class to help me practice. I understand the basic opertoar overload like + - / *, but when I try to overload more complex operator, I get stuck. Here's a brief description what I want to do. I want to simulate a matrix (2D array) from a 1D array. so what I have so far is something like this: class Matrix
0
1836
by: Martin Magnusson | last post by:
I have defined a number of custom stream buffers with corresponding in and out streams for IO operations in my program, such as IO::output, IO::warning and IO::debug. Now, the debug stream should be disabled in a release build, and to do that efficiently, I suppose I need to overload the << operator. My current implementation of the stream in release mode is posted below. Everything works fine for POD type like bool and int, but the...
3
2957
by: Sensei | last post by:
Hi. I have a problem with a C++ code I can't resolve, or better, I can't see what the problem should be! Here's an excerpt of the incriminated code: === bspalgo.cpp // THAT'S THE BAD FUNCTION!!
6
4430
by: YUY0x7 | last post by:
Hi, I am having a bit of trouble with a specialization of operator<<. Here goes: class MyStream { }; template <typename T> MyStream& operator<<(MyStream& lhs, T const &)
3
18833
by: gugdias | last post by:
I'm coding a simple matrix class, which is resulting in the following error when compiling with g++ 3.4.2 (mingw-special): * declaration of `operator/' as non-function * expected `;' before '<' token <snip> --------------------------------------------------- template <class T> class matriz;
5
2294
by: raylopez99 | last post by:
I need an example of a managed overloaded assignment operator for a reference class, so I can equate two classes A1 and A2, say called ARefClass, in this manner: A1=A2;. For some strange reason my C++.NET 2.0 textbook does not have one. I tried to build one using the format as taught in my regular C++ book, but I keep getting compiler errors. Some errors claim (contrary to my book) that you cannot use a static function, that you must...
8
2490
by: valerij | last post by:
Yes, hi How to write "operator +" and "operator =" functions in a class with a defined constructor? The following code demonstrates that I don't really understand how to do it... I think it has something to do with the compiler calling the destructor twice. Could someone point out where I go wrong? P.S.: The error it gives is "Debug Assertion Failure ....." (at run time) P.P.S: Everything else works just fine (without the use of...
3
3284
by: y-man | last post by:
Hi, I am trying to get an overloaded operator to work inside the class it works on. The situation is something like this: main.cc: #include "object.hh" #include "somefile.hh" object obj, obj2 ;
0
10459
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
1
10187
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
10018
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
9055
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
7553
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6795
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5578
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
4120
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
3735
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.