I've following code:
#include <iostream>
#include <cassert>
class Matrix
{
private:
double m_data[3][3]{};
public:
double& operator()(int row, int col);
};
double& Matrix::operator()(int row, int col)
{
assert(col >= 0 && col < 3);
assert(row >= 0 && row < 3);
return m_data[row][col];
}
int main()
{
Matrix matrix;
matrix(1, 2) = 4.5;
std::cout << matrix(1, 2) << '\n';
return 0;
}
I'm wondering how does following line assigns the 4.5 to m_data[1][2].
matrix(1, 2) = 4.5;
Actually, there is no assignment inside the function double& operator()(int row, int col). It has only return m_data[row][col]; statement. Shouldn't it just return value at m_data[1][2]. In that case it would be 0 by default.
This function:
double& Matrix::operator()(int row, int col)
return a reference of a double variable, not just a value.
matrix(1, 2) = 4.5;
matrix(1, 2) returns a reference of that variable, and that reference get assigned a value, that is 4.5
Related
I want to write a fuction to creat a 3D Matrix,but I have a broblem when I try to display it,Please help me,Thanks.
My teacher gave me his codes.His codes can create a 2D array which has Dynamic memory, I want to change his codes to creat a 3D matrix. When I tried to display the Matrix,I realize the array I created is a 2D array,And Because I just begin to use C++,I can't find my mistake.
/*<Array3D.h>*/
#pragma once
#ifndef _ARRAY_3D_H_
#define _ARRAY_3D_H_
//-----------------------------------------
#include <cassert>
#include <vector>
using namespace std;
template<typename T>
class Array3D
{
public:
typedef Array3D<T> _Myt;
Array3D()
: m_nRows(0)
, m_nCols(0)
, m_nDepths(0)
{}
Array3D(size_t r, size_t c,size_t d)
{
Resize(r, c, d);
}
//Allocating memory size
void Resize(size_t r, size_t c,size_t d)
{
if (r == m_nRows && c == m_nCols && d==m_nDepths) { return; }
bool bValid = r > 0 && c > 0 && d>0;
if (!bValid) return;
m_nRows = r;
m_nCols = c;
m_nDepths = d;
m_v.resize(m_nRows * m_nCols * m_nDepths);
}
const T* operator[](size_t r) const
{
assert(r >= 0 && r < m_nRows);
return &(*(m_v.begin() + (r * m_nCols * m_nDepths)));
}
T* operator[](size_t r)
{
assert(r >= 0 && r < m_nRows);
return &(*(m_v.begin() + (r * m_nCols * m_nDepths)));
}
//Gets the start position of a one-dimensional array
const T* GetRawPointer() const { return &(m_v[0]); }
T* GetRawPointer() { return &(m_v[0]); }
long Rows() const
{
return static_cast<long>(m_nRows);
}
long Cols() const
{
return static_cast<long>(m_nCols);
}
long Depths() const
{
return static_cast<long>(m_nDepths);
}
long TotalSize() const
{
return static_cast<long>(m_nRows * m_nCols * m_nDepths);
}
void ClearUp()
{
m_nRows = 0;
m_nCols = 0;
m_nDepths = 0;
m_v.clear();
}
bool IsEmpty() const { return m_v.empty(); }
protected:
vector<T> m_v;// Internally a one-dimensional is used
size_t m_nRows;
size_t m_nCols;
size_t m_nDepths;
};
<Matrix3D.h>
#pragma once
#include "Array3D.h"
class Matrix3D
{
public:
Matrix3D(int r = 0, int c = 0, int d = 0)
{
setSize(r, c, d);
}
void setSize(int r, int c, int d) { m_data3D.Resize(r, c, d); }
void clear() { m_data3D.ClearUp(); }
int rows() const { return m_data3D.Rows(); }
int cols() const { return m_data3D.Cols(); }
int Depths() const { return m_data3D.Depths(); }
void display() const;
//Operator Overloading
float* operator[](int rIndex) { return m_data3D[rIndex]; }
const float* operator[](int rIndex) const { return m_data3D[rIndex]; }
private:
Array3D<float> m_data3D;
};
#include "Matrix3D.h"
#include <iostream>
using namespace std;
void Matrix3D::display() const
{
if (m_data3D.IsEmpty())
{
cout << "empty matrix" << endl;
return;
}
cout << "------------------------" << endl;
const int rows = this->rows();
const int cols = this->cols();
const int Depths = this->Depths();
cout << rows << "x" << cols << "x" << Depths << endl;
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
for(int k = 0 ;k < Depths; k++)
{
cout << m_data3D[i][j][k] << ' '; /*This section will pose an error "E0142"*/
}
cout << endl;
}
}
}
I am going to guess that your teachers class was Array2D and that you mostly just added m_nDepths to it to turn it into Array3D. If this assumption is not right, then my answer here is most likely going to be completely wrong.
But if I am right, then his operator[] looked something like:
T* operator[](size_t r)
{
assert(r >= 0 && r < m_nRows);
return &(*(m_v.begin() + (r * m_nCols)));
}
Which means that when you then do m_data2D[i][j], what happens is that the first [i] applies to the Array2D. This, as shown above, returns a pointer (in your case likely a float*). The [j] is then applied to this pointer, which results in some pointer arithmetic that results in a float (for a float *x; x[y] means *(x+y)).
In other words, your teacher stores his 2D array line by line in a 1D array, and when you [] into it you get a pointer to the right line that you can then further [] into.
This is all fine.
The problem is when you add a third dimension to this and try the same approach: The first [] still returns a float* (but this time to the correct 2D matrix), the second [] returns a float (the first element in the correct line of the 2D matrix), and the third [] tries to apply to a float - which it cannot, and you get the error.
There are two ways to fix this:
Change the return type of Array3D::operator[] to return some kind of 2D array type whose operator[] works like the original Array2D.
Abandon the operator[] approach and replace it with a member function that takes 3 arguments and returns the correct element right away. I think this is what I would prefer myself.
For the second option, something like (not tested, rather large chance I messed up the order of the arguments):
T element(size_t x, size_t y, size_t z) const
{
assert(x >= 0 && x < m_nDepths);
assert(y >= 0 && y < m_nCols);
assert(z >= 0 && z < m_nRows);
return *(m_v.begin() + (x * m_nCols * m_nDepths +
y * m_nCols +
z));
}
T& element(size_t x, size_t y, size_t z)
{
assert(x >= 0 && x < m_nDepths);
assert(y >= 0 && y < m_nCols);
assert(z >= 0 && z < m_nRows);
return *(m_v.begin() + (x * m_nCols * m_nDepths +
y * m_nCols +
z));
}
Which turns cout << m_data3D[i][j][k] << ' '; into cout << m_data3D.element(i,j,k) << ' ';
I'm trying to do task in C++. I need create this function:
void fillArray(std::array<std::array<int, maxColumns>, maxRows> array, size_t rows, size_t columns) {
}
Right now my example code looks like this:
#include <iostream>
#include <array>
constexpr int maxColumns = 42;
constexpr int maxRows = 334;
void fillArray(std::array<std::array<int, maxColumns>, maxRows> array, size_t rows, size_t columns) {
}
int main()
{
}
I need to fill the array with numbers from 1 to rows*columns starting from [0][0] and diagonally. How to declare and initialize the function with array in this example and then fill it diagonally? Any help would be greatly appreciated!
It should be
template <std::size_t maxColumns, std::size_t maxRows>
void fillArray(std::array<std::array<int, maxColumns>, maxRows>& array) {
// ...
}
Demo
Let's suppose you use a simple one-dimensional valarray (or array if you insist) of the size width * height wrapped in a class:
class Matrix
{
private:
std::valarray<int> _data;
int _width, _height;
public:
Matrix(int width, int height) : _width(width), _height(height), _data(width * height)
{
}
}
Then you can add a member function that maps x, y coordinates to an item reference:
int& item(int x, int y) { return _data[x + _width * y]; }
... and another one for filling it diagonally like this:
void fillDiagonally(int value = 0, int step = 1)
{
for (int i = 0; i < _height + _width; ++i) {
// calculate starting coordinates (along left edge and then bottom edge)
int row = i < _height ? i : _height - 1;
int col = i < _height ? 0 : i - _height + 1;
// move diagonally up and right until you reach margins, while filling-in values
for (int j = 0; j < _width - col && j <= row; ++j) {
item(col + j, row - j) = value;
value += step;
}
}
}
and use it like this:
int main()
{
Matrix m(8, 5);
m.fillDiagonally(1);
}
This way, you don't need to pass the array as an argument, because it's a part of the class. Otherwise you would have to pass it by reference, like you were suggested above.
In my project, I had an error with a vector that I solved by including this line in the header file:
std::vector<std::vector<int, int>, int> cells;
However, this produced 181 errors, all of them found either in the 'vector' file or the 'xmemory' file. How do I fix these errors?
The first of these errors is: '_Alloc': must be a class or namespace when followed by '::'
My two files:
Cells.cpp
#include "Cells.h"
#include <vector>
vector<vector<int, int>, int> cells; // [[x, y], state]
// initiates the list of cells
void Cells::init(int w, int h, int s) {
cells.clear();
for (int y = s; y <= h; y += s) {
for (int x = s; x <= w; x += s) {
cells.push_back({ x, y }, 0);
}
}
}
// finds the index of a cell given its coordinates
int find(int x, int y) {
for (int i = 0; i < cells.size(); i++) {
if (cells[i][0] == { x, y }) {
return i
}
}
}
void Cells::setState(int x, int y, int s) {
cells[find(x, y)][1] = s;
}
// the logic of the game
int Cells::brain(int x, int y, int s) { // 1 alive 0 dead, s = size + space
vector<int, int, int, int> around;
int tAlive;
// getting the states of all the cells in a 1 cell radius around the focused one
around.push_back(cells[find(x - s, y - s)][1]);
around.push_back(cells[find(x, y - s)][1]);
around.push_back(cells[find(x + s, y - s)][1]);
around.push_back(cells[find(x - s, y)][1]);
around.push_back(cells[find(x + s, y)][1]);
around.push_back(cells[find(x - s, y + s)][1]);
around.push_back(cells[find(x, y + s)][1]);
around.push_back(cells[find(x + s, y + s)][1]);
for (int i = 0; i < 8; i++) {
if (around[i] == 1) {
tAlive++;
}
}
if (cells[find(x, y)][1] == 1) {
if (tAlive <= 1 || tAlive >= 4) {
cells[find(x, y)][1] = 0;
} else {
cells[find(x, y)][1] = 1;
}
} else {
if (tAlive == 3) {
cells[find(x, y)][1] = 1;
}
}
return cells[find(x, y)][1];
}
Cells.h
#pragma once
#include <vector>
class Cells {
public:
std::vector<std::vector<int, int>, int> cells;
void init(int w, int h, int s);
int brain(int x, int y, int s);
void setState(int x, int y, int s);
};
Firstly, vector> isn’t allowed before C++11 standard. So, you could select Properties->Configuration Properties->C/C++->Language->C++ Language Standard and set ISO C++17 Standard (/std:c++17).
Secondly, you could add std:: before vector and ; after return i.
Finally , if you use vector,int>>, you could change cells.push_back({ x, y }, 0); to cells.push_back(make_pair(make_pair(x, y), 0)); and change cells[i][0] == { x, y } to cells.at[i].first.first == x&& cells.at[i].first.second==y.
I have declared a class Image with two operator() functions, one for read-only, the other for read-and-write access.
Here an extract:
class Image {
//...
public:
uint16_t operator()(int x, int y) const
{
return data_[x + y*width_]; // read-only at pixle (x,y)
}
uint16_t & operator()(int x, int y)
{
return data_[x + y*width_]; // read/write to pixle (x,y)
}
//...
}
After this, I declared an object of Image in the main() function and wrote to it (which has to work because of the mentioned public Interface operator()), but several compilers only keep recognizing the first operator() function which has only permission to read.
Example of this:
if (count_alive_neighbors(image, i, j) == 3) {
image(i, j) = 255;
}
My thought was that maybe one could overcome this problem by declaring a pointer and by this changing the value. Code for this:
uint16_t* f = &image(i, j);
*f = 255;
On Microsoft Visual Studio 2015 this first worked tested alone outside the if-loop, but inside the just mentioned function it didn't. But it's not a compiler error, I've tested it with Clang, g++ and MinGW.
All are printing out an error message like this:
error: lvalue required as unary '&' operand
uint16_t* f = &(image(i, j));
^
To sum it up, the question is the following: how could one overcome this problem by not focusing on that pointer declarations, what can one do to tell the compiler which version of operator() it has to use? It doesn't recognize it on its own or maybe I'm not recognizing which settings/code one has to change to make the program work.
Thanks in advance.
edit: whole class definition and function
#include <vector>
#include <string>
#include <stdexcept>
#include <fstream>
#include <cstdint>
class Image
{
int width_;
int height_;
std::vector<uint16_t> data_;
public:
Image()
: width_(0)
, height_(0)
{}
Image(unsigned int width, unsigned int height)
: width_(width)
, height_(height)
, data_(width*height, uint16_t())
{}
int width() const
{
return width_;
}
int height() const
{
return height_;
}
int size() const
{
return width_*height_;
}
void resize(unsigned int new_width, unsigned int new_height)
{
data_.resize(new_width*new_height, uint16_t());
width_ = new_width;
height_ = new_height;
}
uint16_t operator()(int x, int y) const
{
return data_[x + y*width_];
}
uint16_t & operator()(int x, int y)
{
return data_[x + y*width_];
}
uint16_t get_periodic(int x, int y) const
{
int xres = x % width_;
int yres = y % height_;
return data_[xres + yres*width_];
}
};
int count_alive_neighbors(Image const & image, int x, int y) {
int res = 0;
for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1; j++) {
if (image.get_periodic(x + i, y + j) == 255) {
res += 1;
}
}
}
if (image.get_periodic(x, y) == 255) {
res -= 1;
}
}
Image conway_step(Image const & image) {
for (int i = 0; i <= image.width(); i++) {
for (int j = 0; j <= image.height(); j++) {
if (count_alive_neighbors(image, i, j) == 2)
{
}
if (count_alive_neighbors(image, i, j) == 3) {
image(i, j) = 255;
}
if (count_alive_neighbors(image, i, j) < 2) {
image(i, j) = 0;
}
if (count_alive_neighbors(image, i, j) > 3) {
image(i, j) = 255;
}
}
}
}
int main() {
Image img(3, 3); // declaring object
img(3, 3) = 255; /* !ATTENTION! this works, but inside
conway_steps it doesn't */
}
[Based on the comments] conway_step is supposed to make a copy of its argument, modify that copy, and return the copy. Your problem is that you don't make the copy and try to modify the original.
Please change your function signature from
Image conway_step(Image const & image)
to
Image conway_step(Image & const image) //ill formed
or in a better way
Image conway_step(Image & image)
In first case, it is equivalent to const Image & image, so it calls the const qualified operator => image(i, j)=255; => uint16_t=255 => left operand must be l-value error
In second/third case, you declare a const reference to a non const object.
I overloaded an operator [], but it's not working as I would like.
class A{
int *const e;
const int row, column;
public:
int rows() const
{
return row;
}
int columns() const
{
return column;
}
int size() const
{
return row * column;
}
A(int r, int c)
: row(r), column(c), e(new int[r*c])
{
for (int i = 0; i < r*c; i++)
{
e[i] = 0;
}
}
virtual int *const operator[ ](int r)
{
return &e[r*row];
}
}
For example:
If I wrote:
A a(2, 5)
a[0][0] = 1; // OK
a[0][1] = 2; // OK
a[0][2] = 3; // It's assigned a [0][2] == 3 but also [1][0] == 3
I could not find the problem. It should assigned a value 3 only to [0][2]
What's wrong with this code ?
Because a[0][2] and a[1][0] are one and the same. Let's see:
&e[r*row] is the same as &(*(e+(r*row))) (by definition of []) which is the same as (e+(r*row)).
If r is 0, this is just e, and if r is 1, this is (e+row). Which is, given that your row is 2, is e+2.
So a[0] returns e and a[1] returns e+2.
Now a[0][2] is (a[0])[2] is e[2], and a[1][0] is (e+2)[0] is e[2]. See? Same thing.
If row is the number of rows and column is the number of columns, as your intention seems to be, you are better off returning &e[r*column] from your operator[] (because the number of columns is the size of one row).