Массив конвертируется в указатель, но он работает только для одного уровня. Массив массивов не преобразуется в указатель на указатели.
Массив можно преобразовать в указатель, поскольку указатель все еще обеспечивает разумный способ поиска значений массива, но массив массивов - это принципиально иная вещь, чем указатель на указатели. Массив массивов хранится в памяти непрерывно. Например, если у вас было такое определение:
int a[2][2] = {{1,2},{3,4}};
Затем [0] [0] сохраняется в первой ячейке памяти, a [0] [1] сохраняется во второй, a [1] [0] в третьей и a [1] [1] ] в четвертом. Когда вы хотите посмотреть конкретный элемент, например, [i] [j], компилятор может вычислить местоположение, так как он знает размер массивов:
int value = ((int *)a)[i*2+j];
Сравните это с указателем на указатели
* * 1010
Теперь, когда вы используете [i] [j], компилятор не может напрямую знать, где искать. Сначала нужно взглянуть на [0] и посмотреть, куда это указывает, а затем посмотреть во второй раз, чтобы найти значение.
int *ap = a[i];
int value = ap[j];
Поскольку компилятор должен использовать другой способ поиска значений в массивах массивов и указателей на указатели, вы не можете использовать их взаимозаменяемо.
Аналогично, в таком объявлении:
int a[][2] = {{1,2},{3,4}};
Это нормально, чтобы оставить размер первого измерения, потому что компилятор заполнит его для вас, но это работает только для одного уровня. В принципе, компилятор мог бы догадаться, какими должны быть другие измерения, но это действительно было бы отдельным правилом в языке.
Если вы действительно хотите иметь возможность передавать 2D-массив, вы можете сделать это с помощью шаблонного конструктора, например:
template<int rows, int cols>
Matrix(const double (&initComponents)[rows][cols])
{
// initialize matrix elements here
}
И тогда вам даже не нужно явно передавать размер:
double A[][3] = { {2.0, 3.0, 4.0} , {1.0, 3.0, 4.0} , {2.0, 3.0, 4.0} };
Matrix *mtx = new Matrix(A);