c ++, объект класса изменяется при создании нового объекта - PullRequest
0 голосов
/ 17 октября 2018

Я создал матрицу классов, в которой помимо некоторых функций-членов, операторов и конструктора есть две переменные:

int m, которая является измерением (длиной стороны) квадратичной матрицы

double a [], который содержит элементы матрицы.

Пока я создаю только один матричный объект A, кажется, все работает нормально, и все мои операторы-члены и функции работают так, как должны.

Моя проблема в том, что, как только я создаю второй объект B из матрицы классов, изменяются и переменные объекта A.

Соответствующий код выглядит следующим образом:

class Matrix{
    private:
        const int m;
        double a[];
    public:
        Matrix(int inpm);
        void fillMatrix(const double inpa[]);
};
Matrix::Matrix(int inpm): m(inpm){
    a[impm*inpm];
}
void Matrix::fillmatrix(const double inpa[]){
    for (int i ; i<m*m ; i++){
        a[i]=inpa[i];
    }
}

int min =2;
double ain[min*min] = {1,2,3,4};
double bin[min*min] = {5,6,7,8};

Matrix A(min);
Matrix B(min);

A.fillMatrix(ain);
//A looks precisely as it should here:
//m=2, a={1,2,3,4}
B.fillMatrix(bin);
//Here B looks as it should but A has changed to:
//m=0, a={7,8,3,4}

очевидноизменение первого объекта происходит, когда я запускаю fillMatrix () для второго объекта, но я не могу понять, почему, тем более, что m - это постоянное целое число.

Я действительно застрял так благодарен за любую помощь.

PS: я использую другую функцию-член "void printMatrix ();"используя std: cout для просмотра значений m и всех элементов в a.

Ответы [ 4 ]

0 голосов
/ 17 октября 2018

Проблема из-за объявления вашего массива.люди называли такое объявление массива «объявлением гибкого массива».И это не сработает, как вы ожидали.плюс есть определенные правила, которым нужно следовать при использовании гибкого массива.Но если вы хотите создать динамический массив, вы можете использовать malloc для динамического создания массива.

0 голосов
/ 17 октября 2018

c++ массивы фактически не допускаются для переменной.Существует множество источников о том, почему массивы переменной длины (vla's) не допускаются .Если вы не хотите использовать массив динамической длины с размером, выбранным во время выполнения, вам нужно выделить немного памяти:

double *a;
...
a = new double[inpm*inpm];

Но это отстой!Теперь вы должны помнить, чтобы удалить и получить доступ правильно и все.Вы можете обернуть эту память в класс для управления этим, и, поскольку это хорошая идея, c ++ предоставляет это как стандарт.Это называется std::vector.Ваш код с радостью сведется к следующему:

class Matrix{
private:
    const int m;
    std::vector<double> a;
public:
    Matrix(int inpm) : m(inpm), a(m * m) {}
0 голосов
/ 17 октября 2018

Я заметил несколько проблем с вашим кодом.Первые несколько уже упоминались другими, такими как ваш член double a[]; Это неинициализировано, и C ++ не допускает векторы переменной длины.Для решения этой проблемы есть два возможных решения, о которых я расскажу в ближайшее время.Другая проблема, о которой упоминали другие, заключается в том, что в вашей функции Matrix::fillMatrix() переменная в вашем цикле for i также неинициализирована, поэтому i может быть чем угодно, и это приведет к неопределенному поведению.

Вот некоторые проблемы, которые не были упомянуты другими:

В своем определении конструктора вы пытаетесь инициализировать m с a[impm*inpm] Я думаю, что это может быть опечатка вваша частьДругой - вы объявляете свою функцию как ::fillMatrix(), но вы определяете ее вне объявления класса как ::fillmatrix().Опять же, я думаю, что это может быть просто опечатка с вашей стороны.

Что касается вышеприведенной проблемы с использованием массивов в C++, то самый простой способ сделать это - это то, что уже заявили другие, и это использоватьstd::vector<type>.


Другой способ - написать класс, который работает аналогично std::vector, но имеет механику матрицы.Ваш класс выглядел бы примерно так с использованием шаблонов: если вы хотите, чтобы контейнер переменной длины во время выполнения, вы должны знать, что его размер во время компиляции, с помощью шаблонов здесь может помочь, так как шаблон должен быть выведен во время компиляции при создании!

template<class T, unsigned N>
class Matrix {
private:
    static const unsigned Stride = N;
    static const unsigned Size = Stride * Stride;
    T data[Size] = {};

public:
    Matrix() {};

    void fillMatrix( const T* dataIn );
    void printMatrix();
};

template<class T, unsigned N>
void Matrix<T, N>::fillMatrix( const T* dataIn ) {
    for( unsigned int i = 0; i < Size; i++ ) {
        this->data[i] = dataIn[i];
    }
}

template<class T, unsigned N>
void Matrix<T, N>::printMatrix() {
    for( unsigned int i = 0; i < Stride; i++ ) {
        for( unsigned int j = 0; j < Stride; j++ ) {
            std::cout << this->data[i*Stride + j] << " ";
        }
        std::cout << '\n';
    }
}

int main() {        
    // 2x2 = 4
    double ain[4] = { 1,2,3,4 };
    double bin[4] = { 5,6,7,8 };

    Matrix<double, 2> A;
    Matrix<double, 2> B;

    A.fillMatrix( ain );
    A.printMatrix();
    std::cout << '\n';

    B.fillMatrix( bin );
    B.printMatrix();
    std::cout << '\n';

    // test A again
    A.printMatrix();
    std::cout << '\n';
    B.printMatrix();
    std::cout << '\n';    

    // Try it with other types
    // 3x3 = 9
    char data[9] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i' };
    Matrix<char, 3> C;
    C.fillMatrix( data );
    C.printMatrix();
    std::cout << '\n';

    return 0;
}

Вывод:

1 2 
3 4

5 6
7 8

1 2 
3 4

5 6
7 8

a b c
d e f 
g h i

При таком типе дизайна с использованием шаблонов вы не ограничены использованием только одного type, например int, float и т. Д. Вы даже можете использоватьUser Defined Types.Единственное, что вам нужно учесть, это любой тип operators, который у вас может быть.Кроме того, способ написания этого класса всегда создает матрицу MxM, которая всегда будет квадратной матрицей.Если вам нужна неквадратная матрица;Вы можете просто добавить к этому классу, добавив 2 nd константу без знака в список параметров шаблона и переименовав их соответственно для MxN.Затем просто замените, где они принадлежат в математике.Это будет выглядеть примерно так:

template<class T, unsigned M, unsigned N>
class Matrix {
private:
    static const unsigned Row = M;
    static const unsigned Col = N;
    static const unsigned Size = Row * Col;

    T data[Size] = {};
};

Теперь то, как вы их пометите, может зависеть от того, хотите ли вы Row-Col мажор или Col-Row мажор ...

0 голосов
/ 17 октября 2018

a[impm*inpm]; Это не делает то, что вы думаете.GCC даже предупреждает с statement has no effect.

a здесь остается неинициализированным, и вы сталкиваетесь с неопределенным поведением при попытке доступа к a[i]

class Matrix{
private:
    const int m;
    double *a;
    ....

и

Matrix::Matrix(int inpm): m(inpm)
{
   a = new double[inpm*inpm];
}

и затем не забудьте delete

Matrix::~Matrix()
{
   delete a;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...