Question:
C++ newbie needs help understanding template class/2D array example?
RBS
2009-11-30 06:56:40 UTC
Hi all:

I am a C++ newbie. I would really appreciate some help with understanding an example I found of how to create a 2D array. I know that there are other methods out there, but this is the one I'd like to go with. My goal is to make a 2D grid where the values in the struct Props are at each grid point (I ultimately want to solve a finite difference problem). Thanks for any advice!

The example is below. What I don't understand is the following:
1) T& operator(double x, double y) { return grid_[ y*xsize_ + x ]; } What does this mean? Translation anyone? Where are the variables x and y coming from and what are they for? They don't appear anywhere else/don't seem to be declared.

2) double Row() const { return xsize_; } What does this mean?

3) Why is the Delete() function needed?

4) In the Make, Resize, and Delete functions, why are xsize_ and ysize_ defined? Why not just use row and col?

5) The code as written makes a 1-D array of xsize_ and y_size. Where (e.g., in main(), in the class definition) and how can I say how I want the grid sized? If anyone could offer and example, that would be great.

The code example is below:

template
class Grid2D
{
public:
Grid2D()
: xsize_(0), ysize_(0), grid_(0)
{ }
Grid2D(double row, double col)
: xsize_(row), ysize_(col), grid_(new T[ xsize_ * ysize_ ])
{ }

~Grid2D() { delete[ ] grid_; }

Make(double row, double col)
{
xsize_ = row;
ysize_ = col;
grid_ = new T[ xsize_ * ysize_ ]; /
}
Resize(double row, double col)
{
xsize_ = row;
ysize_ = col;
delete[ ] grid_;
grid_ = new T[ xsize_ * ysize_ ];
}
Delete()
{
xsize_ = 0;
ysize_ = 0;
delete[ ] grid_;
grid_ = 0;
}
double Row() const { return xsize_; }
double Col() const { return ysize_; }
T& operator(double x, double y) { return grid_[ y*xsize_ + x ]; } // Overload x and y
const T& operator(double x, double y) const { return grid_[ y*xsize_ + x ]; }
private:
double xsize_, ysize_;
T* grid_;
}
// T grid[10][10];

//------------------------------------

struct Props
{
double foo;
double bar; // … etc
};

//---------------------------------

int main()
{
// make a grid of Props
Grid2D grid;
Three answers:
cja
2009-11-30 09:32:30 UTC
The class Grid2D needs a few tweaks, which may be contributing to your confusion. It's unfortunate if someone was suggesting that this is a correct template class. It's fundamentally ok, just not usable as-is. My fixes are shown below.



Answers to your questions:



1) This is attempting to overload operator( ), used for indexing into the matrix and returning a reference to the T object at row x, column y. Unfortunately, the syntax of the definition is wrong.



2) This operation returns the number of rows in the matrix.



3) If you default-construct a Grid2D, you need to call the Make operation to give it dimensions and to have the grid_ array allocated. In order to clean this up when you're done with that object, you need to call Delete.



4) The attributes xsize_ and ysize_ need to be set when creating and resizing a Grid2D, and cleared when the grid_ array is deallocated in Delete. They are the dimensions of the matrix.



5) Example below.



My repairs to Grid2D:



#ifndef _GRID2D_H

#define _GRID2D_H



template

class Grid2D {

  public:

    Grid2D() : xsize_(0), ysize_(0), grid_(0) { }

        Grid2D(size_t row, size_t col)

            : xsize_(row), ysize_(col), grid_(new T[ xsize_ * ysize_ ])

            { }

            ~Grid2D() { delete[ ] grid_; }



            void Make(size_t row, size_t col) {

                xsize_ = row;

                ysize_ = col;

                grid_ = new T[ xsize_ * ysize_ ];

            }



            void Resize(double row, double col) {

                xsize_ = row;

                ysize_ = col;

                delete[ ] grid_;

                grid_ = new T[ xsize_ * ysize_ ];

            }

            void Delete() {

                xsize_ = 0;

                ysize_ = 0;

                delete[ ] grid_;

                grid_ = 0;

            }

            size_t Row() const { return xsize_; }

            size_t Col() const { return ysize_; }

            T& operator()(size_t x, size_t y) {

                return grid_[ y*xsize_ + x ];

            }

            const T& operator()(size_t x, size_t y) const {

                return grid_[ y*xsize_ + x ];

            }

  private:

            size_t xsize_, ysize_;

            T* grid_;

};



#endif



Usage example:



#include

#include

#include "grid2d.h"



using namespace std;



struct Complex {

    double real;

    double imag;

    Complex(double r, double i) : real(r), imag(i) { }

    Complex() : real(0.0), imag(0.0) { }

};



int main(int argc, char *argv[]) {

    Grid2D cMat1;

    Grid2D cMat2(2,3);



    cout << "Dimensions of cMat1: " << cMat1.Row()

              << "x" << cMat1.Col() << endl;

    cMat1.Make(1,2);



    cout << "After cMat1.Make(1,2) call ..." << endl;

    cout << "Dimensions of cMat1: " << cMat1.Row()

              << "x" << cMat1.Col() << endl;



    cout << "Dimensions of cMat2: " << cMat2.Row()

              << "x" << cMat2.Col() << endl;



    cMat1(0,0) = Complex(0.1,0.2);

    cMat2(1,2) = Complex(1.1,2.2);



    cout << cMat1(0,0).real << showpos

              << cMat1(0,0).imag << endl;

    cout << noshowpos << cMat2(1,2).real

              << showpos << cMat2(1,2).imag << endl;



    cMat2.Delete();



    return 0;

}



#if 0



Program output:



Dimensions of cMat1: 0x0

After cMat1.Make(1,2) call ...

Dimensions of cMat1: 1x2

Dimensions of cMat2: 2x3

0.1+0.2

1.1+2.2



#endif
2009-11-30 09:43:11 UTC
1) I'm not sure where you got that line from, but that's operator overloading. You need an operator after the operator keyword which is what you are overloading. Because it is not obvious from the function itself what you are trying to do I recommend you replace the operator keyword with a meaningful function name.

This function is returning a reference to your templated grid cell. The variables x and y are being passed in from another function, but it doesn't matter what they were called before because x and y have been created to hold those values for the duration of this function.



2) double Row() const {return xsize_;} is a function that returns the xsize_ variable. It returns a double and the const declaration states that this function cannot change any data inside theGrid2D class. This is a method of making programs easier to debug.



3) The delete function isn't really needed, because the deconstructor supplies the 'delete' to balance the 'new'. However it is good practice to make sure you are cleaning up your stuff manually rather than relying on a deconstuctor to clean up for you.



4) row and col are variables that will cease to exist when the function ends. Thus they cannot be used later and their values must be stored in something more permanent in this case the xsize_ and ysize_ variables which are guaranteed to persist for as long as the Grid2D instance exists (although they may change).



5)having declared the grid in main (not sure if there was meant to be more code), immediately write: grid.make(5, 10); This will create a grid with 5 rows and 10 columns.



On a side note, you will probably find you need to change (at least) the xsize_ and ysize_ double's to int's, because an array (in this case grid_) cannot be indexed using a double.
brignac
2016-10-17 10:43:33 UTC
in this occasion, you're overloading the * operator, for the class wood. you have the desire to make constructive that your operator function isn't waiting to alter something it is going to no longer, so as that there are no longer any unanticipated side effects. to work out why you like this, think of roughly what a binary * operator commonly does -- in case you have been to call this on integers a * b, you won't want the two a or b to get replaced by the operation (as lhs and rhs consult from the left-hand side and precise-hand fringe of the unique expression). i've got faith that making the end result additionally be consistent might upload yet another layer of protection against side effects, struggling with unintended "tricks" by which between the operands can get replaced by getting used because of the fact the left hand fringe of the calling expression. you won't desire to be waiting to declare (a * b) = c, because of the fact it extremely is attempting to assign a sparkling value (the value of "c") to an extremely expression, "a * b." yet you won't be in a position to assign a value to "a * b" -- how might you enforce it? the place might you shop the end result? you have the desire to easily remember to can attempt to assign a value just to an suited variable.


This content was originally posted on Y! Answers, a Q&A website that shut down in 2021.
Loading...