c ++,创建新对象时类的对象会更改

时间:2018-10-17 07:12:14

标签: c++ c++11

我创建了一个类矩阵,除具有一些成员函数外,运算符和构造函数还具有两个变量:

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 :(得分:3)

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;
}

答案 1 :(得分:3)

c++数组实际上是不允许变量的。有plenty of sources about why variable length arrays (vla's) are not allowed。如果您不需要在运行时选择大小的动态长度数组,则需要分配一些内存:

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) {}

答案 2 :(得分:0)

我注意到您的代码存在一些问题。其他人(例如您的成员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

使用模板进行这种类型的设计时,您不仅限于仅使用typeint等单个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专业...

答案 3 :(得分:0)

问题是由于您的数组声明。人们过去将这种数组声明称为“灵活数组声明”。而且它不会按您预期的那样工作。另外,使用灵活数组时要遵循某些规则。 但是,如果要创建动态数组,可以使用malloc动态创建数组。